add initial servehttp

This commit is contained in:
zongor 2023-03-18 22:26:32 -04:00
parent ec4f3c8341
commit 98617309c4
6 changed files with 92 additions and 89 deletions

28
.vscode/launch.json vendored Executable file → Normal file
View File

@ -1,16 +1,16 @@
{ {
// Use IntelliSense to learn about possible attributes. // Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes. // Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "Launch Package", "name": "Launch Package",
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "auto", "mode": "auto",
"program": "main.go", "program": "main.go",
"args": ["examples/test.vqe"] "args": ["examples/http_hello_world.vqe"]
}, }
] ]
} }

View File

@ -0,0 +1,8 @@
{
"<!DOCTYPE html>" disp newline
"<html>" disp newline
"<body>" disp newline
"<h1>nuqneH 'u'?</h1>" disp newline
"</body>" disp newline
"</html>" disp
} ":3333" servehttp

5
main.go Executable file → Normal file
View File

@ -20,8 +20,8 @@ func main() {
func repl() { func repl() {
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)
fmt.Print("> ")
for scanner.Scan() { for scanner.Scan() {
fmt.Print("> ")
line := scanner.Text() line := scanner.Text()
if len(line) == 0 { if len(line) == 0 {
return return
@ -30,7 +30,6 @@ func repl() {
if err != nil { if err != nil {
fmt.Printf("%v\n", err) fmt.Printf("%v\n", err)
} }
fmt.Print("> ")
} }
} }
@ -55,7 +54,7 @@ func interpret(src string) error {
} }
code := varaq.Parse(tokens) code := varaq.Parse(tokens)
err = varaq.Interpret(code, os.Args[1:]) err = varaq.Interpret(code, os.Args[1:], os.Stdout)
if err != nil { if err != nil {
fmt.Printf("%v\n", err) fmt.Printf("%v\n", err)
return err return err

119
varaq/interpreter.go Executable file → Normal file
View File

@ -3,9 +3,11 @@ package varaq
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"io"
"math" "math"
"math/rand" "math/rand"
"net" "net"
"net/http"
"os" "os"
"strconv" "strconv"
"strings" "strings"
@ -46,14 +48,14 @@ func pop() (Expr, error) {
return res, nil return res, nil
} }
func identifierToObj(c Expr, idx int, argv []string) error { func identifierToObj(c Expr, idx int, argv []string, w io.Writer) error {
k, k_ok := c.Value.(string) k, k_ok := c.Value.(string)
if k_ok { if k_ok {
o := get(k) o := get(k)
if o.Tok == UNDEFINED { if o.Tok == UNDEFINED {
return fmt.Errorf("identifier %s undefined @%v", k, idx) return fmt.Errorf("identifier %s undefined @%v", k, idx)
} else if o.Tok == FUNCTION { } else if o.Tok == FUNCTION {
e := Interpret(o, argv) e := Interpret(o, argv, w)
if e != nil { if e != nil {
if e == fmt.Errorf("escape") { if e == fmt.Errorf("escape") {
return nil return nil
@ -70,8 +72,8 @@ func identifierToObj(c Expr, idx int, argv []string) error {
return nil return nil
} }
func (c Expr) idToExpr(idx int, argv []string) (Expr, error) { func (c Expr) idToExpr(idx int, argv []string, w io.Writer) (Expr, error) {
e := identifierToObj(c, idx, argv) e := identifierToObj(c, idx, argv, w)
if e != nil { if e != nil {
return Expr{UNDEFINED, nil, nil, 0}, e return Expr{UNDEFINED, nil, nil, 0}, e
} }
@ -84,8 +86,8 @@ func (c Expr) idToExpr(idx int, argv []string) (Expr, error) {
return vv, nil return vv, nil
} }
func (c Expr) idToS(idx int, argv []string) (string, error) { func (c Expr) idToS(idx int, argv []string, w io.Writer) (string, error) {
v, e := c.idToExpr(idx, argv) v, e := c.idToExpr(idx, argv, w)
if e != nil { if e != nil {
return "", e return "", e
} }
@ -93,13 +95,13 @@ func (c Expr) idToS(idx int, argv []string) (string, error) {
return fmt.Sprintf("%b", v.Value), nil return fmt.Sprintf("%b", v.Value), nil
} }
func popArgs(idx int, argv []string) (Expr, Expr, error) { func popArgs(idx int, argv []string, w io.Writer) (Expr, Expr, error) {
b, e := pop() b, e := pop()
if e != nil { if e != nil {
return Expr{UNDEFINED, nil, nil, 0}, Expr{UNDEFINED, nil, nil, 0}, e return Expr{UNDEFINED, nil, nil, 0}, Expr{UNDEFINED, nil, nil, 0}, e
} }
if b.Tok == IDENTIFIER { if b.Tok == IDENTIFIER {
b, e = b.idToExpr(idx, argv) b, e = b.idToExpr(idx, argv, w)
if e != nil { if e != nil {
return Expr{UNDEFINED, nil, nil, 0}, Expr{UNDEFINED, nil, nil, 0}, e return Expr{UNDEFINED, nil, nil, 0}, Expr{UNDEFINED, nil, nil, 0}, e
} }
@ -109,7 +111,7 @@ func popArgs(idx int, argv []string) (Expr, Expr, error) {
return Expr{UNDEFINED, nil, nil, 0}, Expr{UNDEFINED, nil, nil, 0}, e return Expr{UNDEFINED, nil, nil, 0}, Expr{UNDEFINED, nil, nil, 0}, e
} }
if a.Tok == IDENTIFIER { if a.Tok == IDENTIFIER {
a, e = a.idToExpr(idx, argv) a, e = a.idToExpr(idx, argv, w)
if e != nil { if e != nil {
return Expr{UNDEFINED, nil, nil, 0}, Expr{UNDEFINED, nil, nil, 0}, e return Expr{UNDEFINED, nil, nil, 0}, Expr{UNDEFINED, nil, nil, 0}, e
} }
@ -118,7 +120,7 @@ func popArgs(idx int, argv []string) (Expr, Expr, error) {
return a, b, nil return a, b, nil
} }
func Interpret(code Expr, argv []string) error { func Interpret(code Expr, argv []string, w io.Writer) error {
for idx, c := range code.Exprs { for idx, c := range code.Exprs {
switch c.Tok { switch c.Tok {
case NUMBER: case NUMBER:
@ -170,33 +172,6 @@ func Interpret(code Expr, argv []string) error {
push(stack[n-2]) push(stack[n-2])
stack = append(stack[:n-2], stack[n-3:]...) stack = append(stack[:n-2], stack[n-3:]...)
case PICK:
n := len(stack) - 1
a, e := pop()
if e != nil {
return e
}
if a.Tok == IDENTIFIER {
a = get(a.Value.(string))
}
if a.Tok == NUMBER {
idx := int(a.Value.(float64))
if idx <= 0 {
return fmt.Errorf("`pick`: index must be a positive nonzero value")
}
if n-idx < 0 {
return fmt.Errorf("`pick`: stack underflow")
}
if idx > n {
return fmt.Errorf("`pick`: stack overflow")
}
push(stack[n-idx])
} else {
return fmt.Errorf("cannot `pick` index is not a number @%v", idx)
}
case DEPTH: case DEPTH:
push(Expr{NUMBER, nil, float64(len(stack)), 0}) push(Expr{NUMBER, nil, float64(len(stack)), 0})
case CLEAR: case CLEAR:
@ -206,7 +181,7 @@ func Interpret(code Expr, argv []string) error {
if idx-1 >= 0 && code.Exprs[idx-1].Tok == TILDE { if idx-1 >= 0 && code.Exprs[idx-1].Tok == TILDE {
push(c) push(c)
} else { } else {
e := identifierToObj(c, idx, argv) e := identifierToObj(c, idx, argv, w)
if e != nil { if e != nil {
return e return e
} }
@ -229,9 +204,9 @@ func Interpret(code Expr, argv []string) error {
} }
case DUMP: case DUMP:
for n := len(stack) - 1; n >= 0; n-- { for n := len(stack) - 1; n >= 0; n-- {
fmt.Println(stack[n]) fmt.Fprintf(w, "%v\n", stack[n])
} }
fmt.Println("=== end of dump ===") fmt.Fprintf(w, "=== end of dump ===\n")
case NAME: case NAME:
fun, e := pop() fun, e := pop()
if e != nil { if e != nil {
@ -273,7 +248,7 @@ func Interpret(code Expr, argv []string) error {
} }
if fun.Tok == FUNCTION && logical.Tok == BOOLEAN { if fun.Tok == FUNCTION && logical.Tok == BOOLEAN {
if logical.Value.(bool) { if logical.Value.(bool) {
Interpret(fun, argv) Interpret(fun, argv, w)
} }
} else { } else {
return fmt.Errorf("cannot `ifyes` not a function or bool @%v", idx) return fmt.Errorf("cannot `ifyes` not a function or bool @%v", idx)
@ -289,7 +264,7 @@ func Interpret(code Expr, argv []string) error {
} }
if fun.Tok == FUNCTION && logical.Tok == BOOLEAN { if fun.Tok == FUNCTION && logical.Tok == BOOLEAN {
if !logical.Value.(bool) { if !logical.Value.(bool) {
Interpret(fun, argv) Interpret(fun, argv, w)
} }
} else { } else {
return fmt.Errorf("cannot `ifno` not a function or bool @%v", idx) return fmt.Errorf("cannot `ifno` not a function or bool @%v", idx)
@ -311,7 +286,7 @@ func Interpret(code Expr, argv []string) error {
return e return e
} }
if fun.Tok == FUNCTION { if fun.Tok == FUNCTION {
Interpret(fun, argv) Interpret(fun, argv, w)
} else { } else {
return fmt.Errorf("cannot `eval` not a function @%v", idx) return fmt.Errorf("cannot `eval` not a function @%v", idx)
} }
@ -328,7 +303,7 @@ func Interpret(code Expr, argv []string) error {
} }
if fun.Tok == FUNCTION && count.Tok == NUMBER { if fun.Tok == FUNCTION && count.Tok == NUMBER {
for n := int64(0); n < int64(count.Value.(float64)); n++ { for n := int64(0); n < int64(count.Value.(float64)); n++ {
err := Interpret(fun, argv) err := Interpret(fun, argv, w)
if err != nil { if err != nil {
return err return err
} }
@ -436,7 +411,7 @@ func Interpret(code Expr, argv []string) error {
var v2_s string var v2_s string
if v1.Tok == IDENTIFIER { if v1.Tok == IDENTIFIER {
v1_s, e = v1.idToS(idx, argv) v1_s, e = v1.idToS(idx, argv, w)
if e != nil { if e != nil {
return e return e
} }
@ -462,7 +437,7 @@ func Interpret(code Expr, argv []string) error {
} }
if v2.Tok == IDENTIFIER { if v2.Tok == IDENTIFIER {
v2_s, e = v2.idToS(idx, argv) v2_s, e = v2.idToS(idx, argv, w)
if e != nil { if e != nil {
return e return e
} }
@ -530,7 +505,7 @@ func Interpret(code Expr, argv []string) error {
} }
} }
case ADD: case ADD:
a, b, e := popArgs(idx, argv) a, b, e := popArgs(idx, argv, w)
if e != nil { if e != nil {
return e return e
} }
@ -541,7 +516,7 @@ func Interpret(code Expr, argv []string) error {
return fmt.Errorf("cannot `add` values are not numbers @%v", idx) return fmt.Errorf("cannot `add` values are not numbers @%v", idx)
} }
case SUB: case SUB:
a, b, e := popArgs(idx, argv) a, b, e := popArgs(idx, argv, w)
if e != nil { if e != nil {
return e return e
} }
@ -552,7 +527,7 @@ func Interpret(code Expr, argv []string) error {
return fmt.Errorf("cannot `sub` values are not numbers @%v", idx) return fmt.Errorf("cannot `sub` values are not numbers @%v", idx)
} }
case MUL: case MUL:
a, b, e := popArgs(idx, argv) a, b, e := popArgs(idx, argv, w)
if e != nil { if e != nil {
return e return e
} }
@ -563,7 +538,7 @@ func Interpret(code Expr, argv []string) error {
return fmt.Errorf("cannot `mul` values are not numbers @%v", idx) return fmt.Errorf("cannot `mul` values are not numbers @%v", idx)
} }
case DIV: case DIV:
a, b, e := popArgs(idx, argv) a, b, e := popArgs(idx, argv, w)
if e != nil { if e != nil {
return e return e
} }
@ -574,7 +549,7 @@ func Interpret(code Expr, argv []string) error {
return fmt.Errorf("cannot `div` values are not numbers @%v", idx) return fmt.Errorf("cannot `div` values are not numbers @%v", idx)
} }
case IDIV: case IDIV:
a, b, e := popArgs(idx, argv) a, b, e := popArgs(idx, argv, w)
if e != nil { if e != nil {
return e return e
} }
@ -585,7 +560,7 @@ func Interpret(code Expr, argv []string) error {
return fmt.Errorf("cannot `idiv` values are not numbers @%v", idx) return fmt.Errorf("cannot `idiv` values are not numbers @%v", idx)
} }
case MOD: case MOD:
a, b, e := popArgs(idx, argv) a, b, e := popArgs(idx, argv, w)
if e != nil { if e != nil {
return e return e
} }
@ -596,7 +571,7 @@ func Interpret(code Expr, argv []string) error {
return fmt.Errorf("cannot `mod` values are not numbers @%v", idx) return fmt.Errorf("cannot `mod` values are not numbers @%v", idx)
} }
case POW: case POW:
a, b, e := popArgs(idx, argv) a, b, e := popArgs(idx, argv, w)
if e != nil { if e != nil {
return e return e
} }
@ -1215,15 +1190,15 @@ func Interpret(code Expr, argv []string) error {
return e return e
} }
if a.Tok == IDENTIFIER { if a.Tok == IDENTIFIER {
fmt.Printf("%v\n", get(a.Value.(string))) fmt.Fprintf(w, "%v", get(a.Value.(string)))
} else if a.Tok == NUMBER { } else if a.Tok == NUMBER {
if a.Value.(float64) == float64(int64(a.Value.(float64))) { if a.Value.(float64) == float64(int64(a.Value.(float64))) {
fmt.Printf("%d\n", int64(a.Value.(float64))) fmt.Fprintf(w, "%d", int64(a.Value.(float64)))
} else { } else {
fmt.Printf("%f\n", a.Value.(float64)) fmt.Fprintf(w, "%f", a.Value.(float64))
} }
} else { } else {
fmt.Printf("%v\n", a.Value) fmt.Fprintf(w, "%v", a.Value)
} }
case LISTEN: case LISTEN:
var str string var str string
@ -1245,9 +1220,9 @@ func Interpret(code Expr, argv []string) error {
} }
fmt.Fprintf(os.Stderr, "%v", a.Value) fmt.Fprintf(os.Stderr, "%v", a.Value)
case NEWLINE: case NEWLINE:
fmt.Println() fmt.Fprintf(w, "\n")
case TAB: case TAB:
fmt.Println("\t") fmt.Fprintf(w, "\t")
case WHEREAMI: case WHEREAMI:
conn, e := net.Dial("udp", "8.8.8.8:80") conn, e := net.Dial("udp", "8.8.8.8:80")
if e != nil { if e != nil {
@ -1257,9 +1232,31 @@ func Interpret(code Expr, argv []string) error {
localAddr := conn.LocalAddr().(*net.UDPAddr) localAddr := conn.LocalAddr().(*net.UDPAddr)
fmt.Println(localAddr.IP.String()) fmt.Fprintf(w, "%s\n", localAddr.IP.String())
case SERVEHTTP:
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)
}
http.ListenAndServe(str.Value.(string), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fun, e := pop()
if e != nil {
return
}
if fun.Tok == FUNCTION {
Interpret(fun, nil, w)
} else {
return
}
}))
case VERSION: case VERSION:
fmt.Println("var'aq -- 0.9.1 Martoq") fmt.Fprintf(w, "var'aq -- 0.9.1 Martoq")
case ARGV: case ARGV:
arg := Expr{LIST, make([]Expr, 0), nil, 0} arg := Expr{LIST, make([]Expr, 0), nil, 0}
for _, v := range argv { for _, v := range argv {

15
varaq/scanner.go Executable file → Normal file
View File

@ -175,14 +175,13 @@ var keywords = map[string]TokenType{
"pongmI'": VERSION, "pongmI'": VERSION,
"nuqDaq_jIH": WHEREAMI, "nuqDaq_jIH": WHEREAMI,
// All the ones after this are a part of the var'aq superset // All the ones after this are a part of the var'aq superset
"rot": ROT, "rot": ROT,
"jIr": ROT, "jIr": ROT,
"over": OVER, "over": OVER,
"QI": OVER, "QI": OVER,
"depth": DEPTH, "depth": DEPTH,
"juv": DEPTH, "juv": DEPTH,
"pick": PICK, "servehttp": SERVEHTTP,
"woH": PICK,
} }
func isDigit(s string) bool { func isDigit(s string) bool {

4
varaq/token.go Executable file → Normal file
View File

@ -105,7 +105,7 @@ const (
OVER OVER
ROT ROT
DEPTH DEPTH
PICK SERVEHTTP
) )
var tokens = [...]string{ var tokens = [...]string{
@ -210,7 +210,7 @@ var tokens = [...]string{
OVER: "OVER", OVER: "OVER",
ROT: "ROT", ROT: "ROT",
DEPTH: "DEPTH", DEPTH: "DEPTH",
PICK: "PICK", SERVEHTTP: "SERVEHTTP",
} }
func (me TokenType) String() string { func (me TokenType) String() string {