package varaq import ( "bufio" "fmt" "io" "io/ioutil" "math" "math/rand" "net" "net/http" "os" "runtime" "strconv" "strings" "time" ) var globals = map[string]Expr{} var stack = make([]Expr, 0) var s = bufio.NewScanner(os.Stdin) func get(k string) Expr { return globals[k] } func put(k string, v Expr) { globals[k] = v } func push(o Expr) { stack = append(stack, o) } func top() (Expr, error) { n := len(stack) - 1 if n < 0 { return Expr{}, fmt.Errorf("stack underflow") } return stack[n], nil } func pop() (Expr, error) { res, e := top() if e != nil { return Expr{}, e } n := len(stack) - 1 stack = stack[:n] return res, nil } func popExpr() (Expr, error) { a, e := pop() if e != nil { return Expr{}, e } if a.Tok == IDENTIFIER { a = get(a.Value.(string)) } return a, nil } func pop2Expr() (Expr, Expr, error) { b, e := popExpr() if e != nil { return Expr{}, Expr{}, e } a, e := popExpr() if e != nil { return Expr{}, Expr{}, e } return b, a, nil } func identifierToObj(c Expr, idx int, argv []string, w io.Writer) error { k, k_ok := c.Value.(string) if k_ok { o := get(k) if o.Tok == UNDEFINED { return fmt.Errorf("identifier %s undefined @%v", k, idx) } else if o.Tok == FUNCTION { e := Interpret(o, argv, w) if e != nil { if e == fmt.Errorf("escape") { return nil } return e } } else { push(o) } } else { return fmt.Errorf("idenifier not string @%v", idx) } return nil } func (c Expr) idToExpr(idx int, argv []string, w io.Writer) (Expr, error) { e := identifierToObj(c, idx, argv, w) if e != nil { return Expr{UNDEFINED, nil, nil, 0}, e } vv, e2 := pop() if e2 != nil { return Expr{UNDEFINED, nil, nil, 0}, e2 } return vv, nil } func (c Expr) idToS(idx int, argv []string, w io.Writer) (string, error) { v, e := c.idToExpr(idx, argv, w) if e != nil { return "", e } return fmt.Sprintf("%b", v.Value), nil } func popArgs(idx int, argv []string, w io.Writer) (Expr, Expr, error) { b, e := pop() if e != nil { return Expr{UNDEFINED, nil, nil, 0}, Expr{UNDEFINED, nil, nil, 0}, e } if b.Tok == IDENTIFIER { b, e = b.idToExpr(idx, argv, w) if e != nil { return Expr{UNDEFINED, nil, nil, 0}, Expr{UNDEFINED, nil, nil, 0}, e } } a, e := pop() if e != nil { return Expr{UNDEFINED, nil, nil, 0}, Expr{UNDEFINED, nil, nil, 0}, e } if a.Tok == IDENTIFIER { a, e = a.idToExpr(idx, argv, w) if e != nil { return Expr{UNDEFINED, nil, nil, 0}, Expr{UNDEFINED, nil, nil, 0}, e } } return a, b, nil } func Interpret(code Expr, argv []string, w io.Writer) error { for idx, c := range code.Exprs { switch c.Tok { case NUMBER: push(c) case STRING: push(c) case LIST: push(c) case FUNCTION: push(c) case TRUE: push(Expr{BOOLEAN, nil, true, 0}) case FALSE: push(Expr{BOOLEAN, nil, false, 0}) case POP: _, e := pop() if e != nil { return e } case DUP: obj, e := pop() if e != nil { return e } push(obj) push(obj) case EXCH: obj1, e1 := pop() if e1 != nil { return e1 } obj2, e2 := pop() if e2 != nil { return e2 } push(obj1) push(obj2) case OVER: n := len(stack) - 1 if n-1 < 0 { return fmt.Errorf("over: stack underflow") } push(stack[n-1]) case ROT: n := len(stack) - 1 if n-3 < 0 { return fmt.Errorf("stack underflow, must have 3 or more") } push(stack[n-2]) stack = append(stack[:n-2], stack[n-3:]...) case DEPTH: push(Expr{NUMBER, nil, float64(len(stack)), 0}) case CLEAR: stack = nil stack = make([]Expr, 0) case IDENTIFIER: if idx-1 >= 0 && code.Exprs[idx-1].Tok == TILDE { push(c) } else { e := identifierToObj(c, idx, argv, w) if e != nil { return e } } case REMEMBER: push(Expr{REMEMBER, nil, "REMEMBER", 0}) case FORGET: v, e := pop() if e != nil { return e } for { if v.Tok == REMEMBER || len(stack) == 0 { break } v, e = pop() if e != nil { return e } } case DUMP: for n := len(stack) - 1; n >= 0; n-- { fmt.Fprintf(w, "%v\n", stack[n]) } fmt.Fprintf(w, "=== end of dump ===\n") case NAME: fun, e := pop() if e != nil { return e } name, en := pop() if en != nil { return en } namev, n_ok := name.Value.(string) if fun.Tok == FUNCTION && name.Tok == IDENTIFIER && n_ok { put(namev, fun) } else { return fmt.Errorf("cannot bind name @%v", idx) } case SET: name, en := pop() if en != nil { return en } o, e := pop() if e != nil { return e } n, n_ok := name.Value.(string) if (name.Tok == IDENTIFIER || name.Tok == STRING) && n_ok { put(n, o) } else { return fmt.Errorf("cannot set, name is not a string @%v", idx) } case IFYES: fun, ef := pop() if ef != nil { return ef } logical, el := pop() if el != nil { return el } if fun.Tok == FUNCTION && logical.Tok == BOOLEAN { if logical.Value.(bool) { Interpret(fun, argv, w) } } else { return fmt.Errorf("cannot `ifyes` not a function or bool @%v", idx) } case IFNO: fun, ef := pop() if ef != nil { return ef } logical, el := pop() if el != nil { return el } if fun.Tok == FUNCTION && logical.Tok == BOOLEAN { if !logical.Value.(bool) { Interpret(fun, argv, w) } } else { return fmt.Errorf("cannot `ifno` not a function or bool @%v", idx) } case CHOOSE: b, e := pop() if e != nil { return e } if b.Tok == BOOLEAN { push(b) push(b) } else { return fmt.Errorf("cannot `choose` not a bool @%v", idx) } case EVAL: fun, e := pop() if e != nil { return e } if fun.Tok == FUNCTION { Interpret(fun, argv, w) } else { return fmt.Errorf("cannot `eval` not a function @%v", idx) } case ESCAPE: return fmt.Errorf("escape") case REPEAT: fun, e := pop() if e != nil { return e } count, ec := pop() if ec != nil { return ec } if fun.Tok == FUNCTION && count.Tok == NUMBER { for n := int64(0); n < int64(count.Value.(float64)); n++ { err := Interpret(fun, argv, w) if err != nil { return err } } } else { return fmt.Errorf("cannot `repeat` not a function or int @%v", idx) } case SPLIT: list, e := pop() if e != nil { return e } if list.Tok == LIST { n := len(list.Exprs) - 1 e := list.Exprs[n] list.Exprs = list.Exprs[:n] push(list) push(e) } else { return fmt.Errorf("cannot `split` not a list @%v", idx) } case CONS: o, eo := pop() if eo != nil { return eo } list, e := pop() if e != nil { return e } if list.Tok == LIST { list.Exprs = append(list.Exprs, o) push(list) } else { return fmt.Errorf("cannot `cons` not a list @%v", idx) } case SHATTER: list, e := pop() if e != nil { return e } if list.Tok == LIST { for n := 0; n < len(list.Exprs); n++ { push(list.Exprs[n]) } } else { return fmt.Errorf("cannot `shatter` not a list @%v", idx) } case MEASURE: list, e := pop() if e != nil { return e } if list.Tok == LIST { push(Expr{NUMBER, nil, float64(len(list.Exprs)), 0}) } else { return fmt.Errorf("cannot `measure` not a list @%v", idx) } case EMPTY: list, e := pop() if e != nil { return e } if list.Tok == LIST { push(Expr{BOOLEAN, nil, len(list.Exprs) == 0, 0}) } else { return fmt.Errorf("cannot `empty` not a list @%v", idx) } case COMPOSE: v, e := pop() if e != nil { return e } var sb strings.Builder for { if v.Tok == REMEMBER || len(stack) == 0 { break } v, e := pop() if e != nil { return e } if v.Tok == STRING { sb.WriteString(v.Value.(string)) } else { return fmt.Errorf("cannot `compose` value is not a string @%v", idx) } } push(Expr{STRING, nil, sb.String(), 0}) case STREQ: v1, e := pop() if e != nil { return e } v2, e2 := pop() if e2 != nil { return e2 } if v1.Tok == STRING && v2.Tok == STRING { push(Expr{BOOLEAN, nil, v1.Value.(string) == v2.Value.(string), 0}) } else { return fmt.Errorf("cannot `streq?` value is not a string @%v", idx) } case STRTIE: var e error v2, e := pop() if e != nil { return e } v1, e := pop() if e != nil { return e } var v1_s string var v2_s string if v1.Tok == IDENTIFIER { v1_s, e = v1.idToS(idx, argv, w) if e != nil { return e } } else if v1.Tok == STRING { v1_s = v1.Value.(string) } else { var d float64 err := false switch v := v1.Value.(type) { case float64: d = float64(v) default: err = true } if err { v1_s = fmt.Sprintf("%v", v1.Value) } else if d == float64(int64(d)) { v1_s = fmt.Sprintf("%d", int64(v1.Value.(float64))) } else { v1_s = fmt.Sprintf("%f", v1.Value.(float64)) } } if v2.Tok == IDENTIFIER { v2_s, e = v2.idToS(idx, argv, w) if e != nil { return e } } else if v2.Tok == STRING { v2_s = v2.Value.(string) } else { var d float64 err := false switch v := v2.Value.(type) { case float64: d = float64(v) default: err = true } if err { v2_s = fmt.Sprintf("%v", v2.Value) } else if d == float64(int64(d)) { v2_s = fmt.Sprintf("%d", int64(v2.Value.(float64))) } else { v2_s = fmt.Sprintf("%f", v2.Value.(float64)) } } push(Expr{STRING, nil, v1_s + v2_s, 0}) case STRCUT: endval, e := pop() if e != nil { return e } startval, e := pop() if e != nil { return e } str, e := pop() if e != nil { return e } if str.Tok == STRING && startval.Tok == NUMBER && endval.Tok == NUMBER { push(Expr{STRING, nil, str.Value.(string)[int64(startval.Value.(float64)):int64(endval.Value.(float64))], 0}) } else { return fmt.Errorf("cannot `strcut` value is not a string or start/end val is not an int @%v", idx) } case STRMEASURE: v, e := pop() if e != nil { return e } if v.Tok == STRING { push(Expr{NUMBER, nil, float64(len(v.Value.(string))), 0}) } else { return fmt.Errorf("cannot `strmeasure` value is not a string @%v", idx) } case EXPLODE: str, e := pop() if e != nil { return e } if str.Tok == STRING { words := strings.Fields(str.Value.(string)) for _, s := range words { push(Expr{STRING, nil, s, 0}) } } case ADD: a, b, e := popArgs(idx, argv, w) if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{NUMBER, nil, a.Value.(float64) + (b.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `add` values are not numbers @%v", idx) } case SUB: a, b, e := popArgs(idx, argv, w) if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{NUMBER, nil, a.Value.(float64) - (b.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `sub` values are not numbers @%v", idx) } case MUL: a, b, e := popArgs(idx, argv, w) if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{NUMBER, nil, a.Value.(float64) * (b.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `mul` values are not numbers @%v", idx) } case DIV: a, b, e := popArgs(idx, argv, w) if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{NUMBER, nil, a.Value.(float64) / (b.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `div` values are not numbers @%v", idx) } case IDIV: a, b, e := popArgs(idx, argv, w) if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{NUMBER, nil, math.Round(a.Value.(float64)) / math.Round(b.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `idiv` values are not numbers @%v", idx) } case MOD: a, b, e := popArgs(idx, argv, w) if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{NUMBER, nil, float64(int64(a.Value.(float64)) % int64(b.Value.(float64))), 0}) } else { return fmt.Errorf("cannot `mod` values are not numbers @%v", idx) } case POW: a, b, e := popArgs(idx, argv, w) if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{NUMBER, nil, math.Pow(a.Value.(float64), b.Value.(float64)), 0}) } case SQRT: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { push(Expr{NUMBER, nil, math.Sqrt(a.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `sqrt` value is not number or float @%v", idx) } case ADD1: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { push(Expr{NUMBER, nil, a.Value.(float64) + 1.0, 0}) } else { return fmt.Errorf("cannot `add1` value is not a number @%v", idx) } case SUB1: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { push(Expr{NUMBER, nil, a.Value.(float64) - 1.0, 0}) } else { return fmt.Errorf("cannot `sub1` value is not a number @%v", idx) } case SIN: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { push(Expr{NUMBER, nil, math.Sin(a.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `sin` values are not numbers or floats @%v", idx) } case COS: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { push(Expr{NUMBER, nil, math.Cos(a.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `cos` values are not numbers or floats @%v", idx) } case TAN: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { push(Expr{NUMBER, nil, math.Tan(a.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `tan` values are not numbers or floats @%v", idx) } case ATAN: a, e := popExpr() if e != nil { return e } den, e := pop() if e != nil { return e } if den.Tok == IDENTIFIER { den = get(den.Value.(string)) } if a.Tok == NUMBER && den.Tok == NUMBER { push(Expr{NUMBER, nil, math.Atan(a.Value.(float64) / den.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `atan` values are not numbers or floats @%v", idx) } case LN: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { push(Expr{NUMBER, nil, math.Log(a.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `ln` values are not numbers or floats @%v", idx) } case LOG: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { push(Expr{NUMBER, nil, math.Log10(a.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `log` values are not numbers or floats @%v", idx) } case LOG3: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { push(Expr{NUMBER, nil, math.Log(a.Value.(float64)) / math.Log(3.0), 0}) } else { return fmt.Errorf("cannot `log3` values are not numbers or floats @%v", idx) } case CLIP: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { push(Expr{NUMBER, nil, math.Floor(a.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `clip` values are not numbers or floats @%v", idx) } case SMOOTH: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { push(Expr{NUMBER, nil, math.Round(a.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `smooth` values are not numbers or floats @%v", idx) } case HOWMUCH: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { push(Expr{NUMBER, nil, math.Abs(a.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `howmuch` values are not numbers or floats @%v", idx) } case SETRAND: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { rand.Seed(int64(a.Value.(float64))) } else { return fmt.Errorf("cannot `setrand` values are not numbers or floats @%v", idx) } case RAND: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { max := a.Value.(float64) r := rand.Intn(int(max)) push(Expr{NUMBER, nil, float64(r), 0}) } else { return fmt.Errorf("cannot `rand` values are not numbers or floats @%v", idx) } case PI: push(Expr{NUMBER, nil, 3.14159265358979323846, 0}) case E: push(Expr{NUMBER, nil, 2.71828182845904523536, 0}) case ISINT: a, e := popExpr() if e != nil { return e } push(Expr{BOOLEAN, nil, a.Value.(float64) == float64(int64(a.Value.(float64))), 0}) case ISNUMBER: a, e := popExpr() if e != nil { return e } push(Expr{BOOLEAN, nil, (a.Tok == NUMBER), 0}) case NUMBERIZE: str, e := pop() if e != nil { return e } if str.Tok != STRING { return fmt.Errorf("cannot `numberize` not a string @%v", idx) } num, err := strconv.ParseFloat(str.Value.(string), 64) if err != nil { return err } push(Expr{NUMBER, nil, num, 0}) case ISOLATE: b, a, e := pop2Expr() if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{NUMBER, nil, float64(int64(a.Value.(float64)) & int64(b.Value.(float64))), 0}) } else { return fmt.Errorf("cannot `isolate` values are not numbers @%v", idx) } case MIX: b, a, e := pop2Expr() if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{NUMBER, nil, float64(int64(a.Value.(float64)) | int64(b.Value.(float64))), 0}) } else { return fmt.Errorf("cannot `mix` values are not numbers @%v", idx) } case CONTRADICT: b, a, e := pop2Expr() if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{NUMBER, nil, float64(int64(a.Value.(float64)) ^ int64(b.Value.(float64))), 0}) } else { return fmt.Errorf("cannot `contradict` values are not numbers @%v", idx) } case COMPL: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { push(Expr{NUMBER, nil, float64(^int64(a.Value.(float64))), 0}) } else { return fmt.Errorf("cannot `compl` values are not numbers @%v", idx) } case SHIFTRIGHT: b, a, e := pop2Expr() if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{NUMBER, nil, float64(int64(a.Value.(float64)) >> int64(b.Value.(float64))), 0}) } else { return fmt.Errorf("cannot `shiftright` values are not numbers @%v", idx) } case SHIFTLEFT: b, a, e := pop2Expr() if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{NUMBER, nil, float64(int64(a.Value.(float64)) << int64(b.Value.(float64))), 0}) } else { return fmt.Errorf("cannot `shiftleft` values are not numbers @%v", idx) } case GT: b, a, e := pop2Expr() if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{BOOLEAN, nil, a.Value.(float64) > (b.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `gt` values are not numbers @%v", idx) } case LT: b, a, e := pop2Expr() if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{BOOLEAN, nil, a.Value.(float64) < (b.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `lt` values are not numbers @%v", idx) } case EQ: b, a, e := pop2Expr() if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{BOOLEAN, nil, a.Value.(float64) == b.Value.(float64), 0}) } else { return fmt.Errorf("cannot `eq` values are not numbers @%v", idx) } case GE: b, a, e := pop2Expr() if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{BOOLEAN, nil, a.Value.(float64) >= (b.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `ge` values are not numbers @%v", idx) } case LE: b, a, e := pop2Expr() if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{BOOLEAN, nil, a.Value.(float64) <= (b.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `le` values are not numbers @%v", idx) } case NE: b, a, e := pop2Expr() if e != nil { return e } if a.Tok == NUMBER && b.Tok == NUMBER { push(Expr{BOOLEAN, nil, a.Value.(float64) != (b.Value.(float64)), 0}) } else { return fmt.Errorf("cannot `ne` values are not numbers @%v", idx) } case ISNULL: a, e := popExpr() if e != nil { return e } push(Expr{BOOLEAN, nil, (a.Tok == NULL || a.Value == nil), 0}) case NEGATIVE: a, e := popExpr() if e != nil { return e } if a.Tok == NUMBER { push(Expr{BOOLEAN, nil, a.Value.(float64) < 0.0, 0}) } else { return fmt.Errorf("cannot `negative` values are not numbers @%v", idx) } case AND: b, a, e := pop2Expr() if e != nil { return e } if a.Tok == BOOLEAN && b.Tok == BOOLEAN { push(Expr{BOOLEAN, nil, (a.Value.(bool) && b.Value.(bool)), 0}) } else { return fmt.Errorf("cannot `and` values are not numbers @%v", idx) } case OR: b, a, e := pop2Expr() if e != nil { return e } if a.Tok == BOOLEAN && b.Tok == BOOLEAN { push(Expr{BOOLEAN, nil, (a.Value.(bool) || b.Value.(bool)), 0}) } else { return fmt.Errorf("cannot `or` values are not numbers @%v", idx) } case XOR: b, a, e := pop2Expr() if e != nil { return e } if a.Tok == BOOLEAN && b.Tok == BOOLEAN { push(Expr{BOOLEAN, nil, (a.Value.(bool) != b.Value.(bool)), 0}) } else { return fmt.Errorf("cannot `xor` values are not numbers @%v", idx) } case DISP: a, e := pop() if e != nil { return e } if a.Tok == IDENTIFIER { fmt.Fprintf(w, "%v", get(a.Value.(string))) } else if a.Tok == NUMBER { if a.Value.(float64) == float64(int64(a.Value.(float64))) { fmt.Fprintf(w, "%d", int64(a.Value.(float64))) } else { fmt.Fprintf(w, "%f", a.Value.(float64)) } } else { fmt.Fprintf(w, "%v", a.Value) } case LISTEN: if runtime.GOARCH == "wasm" { // In WASM mode fetch does a fetch request from a foreign website v1, e := pop() if e != nil { return e } if v1.Tok == STRING { url := v1.Value.(string) resp, err := http.Get(url) if err != nil { // we will get an error at this stage if the request fails, such as if the // requested URL is not found, or if the server is not reachable. return err } defer resp.Body.Close() // print the response data, err := ioutil.ReadAll(resp.Body) if err != nil { return err } push(Expr{STRING, nil, string(data), 0}) } else { return fmt.Errorf("cannot `streq?` value is not a string @%v", idx) } } else { var str string s.Scan() str = s.Text() if s.Err() != nil { return s.Err() } push(Expr{STRING, nil, str, 0}) } case COMPLAIN: a, e := popExpr() if e != nil { return e } fmt.Fprintf(os.Stderr, "%v", a.Value) case NEWLINE: fmt.Fprintf(w, "\n") case TAB: fmt.Fprintf(w, "\t") case WHEREAMI: if runtime.GOARCH == "wasm" { return nil } conn, e := net.Dial("udp", "8.8.8.8:80") if e != nil { return e } defer conn.Close() localAddr := conn.LocalAddr().(*net.UDPAddr) fmt.Fprintf(w, "%s\n", localAddr.IP.String()) case SERVEHTTP: if runtime.GOARCH == "wasm" { return nil } str, e := pop() if e != nil { return e } if str.Tok != STRING { return fmt.Errorf("cannot `servehttp` exptected a string for the port @%v", idx) } fun, e := pop() if e != nil { return e } if fun.Tok != FUNCTION { return fmt.Errorf("cannot `servehttp` exptected a function to serve @%v", idx) } http.ListenAndServe(str.Value.(string), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { req := make([]string, 0) b, err := ioutil.ReadAll(r.Body) if err != nil { fmt.Println(err) return } req = append(req, r.RequestURI) req = append(req, string(b)) req = append(req, r.Method) // maybe should add the headers here // add the number of arguments for the header err = Interpret(fun, req, w) if err != nil { fmt.Println(err) } })) case READALL: str, e := pop() if e != nil { return e } if str.Tok != STRING { return fmt.Errorf("cannot `readall` @%v", idx) } filedata, err := ioutil.ReadFile(str.Value.(string)) // the file is inside the local directory if err != nil { return err } push(Expr{STRING, nil, string(filedata), 0}) case VERSION: fmt.Fprintf(w, "var'aq -- 0.9.2 Martoq") case ARGV: arg := Expr{LIST, make([]Expr, 0), nil, 0} for _, v := range argv { arg.Exprs = append(arg.Exprs, Expr{STRING, nil, v, 0}) } push(arg) case TIME: push(Expr{NUMBER, nil, float64(time.Now().Unix()), 0}) case TILDE: default: return fmt.Errorf("unknown opcode") } } return nil }