| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- package main
- import (
- "bufio"
- "fmt"
- "math/rand"
- "os"
- "strings"
- "time"
- "unicode"
- "unicode/utf8"
- )
- var reserved = map[string]int{
- "make": 2, "thing": 1, "print": 1, "read": 0, "add": 2,
- "sub": 2, "mul": 2, "div": 2, "mod": 2, "erase": 1,
- "isname": 1, "run": 1, "eq": 2, "gt": 2, "lt": 2,
- "and": 2, "or": 2, "not": 1, "if": 3, "isnumber": 1,
- "isword": 1, "islist": 1, "isbool": 1, "isempty": 1, "return": 1,
- "export": 1, "readlist": 0, "word": 2, "sentence": 2, "list": 2,
- "join": 2, "first": 1, "last": 1, "butfirst": 1, "butlast": 1,
- "random": 1, "int": 1, "sqrt": 1, "save": 1, "load": 1,
- "erall": 0, "poall": 0}
- type environ map[string]value
- type value struct {
- val string
- list []string
- param []string
- env environ
- }
- var env []environ
- var stack []value
- func interpret(scanner *bufio.Scanner) (val value, returned bool) {
- stackTop, returned := len(stack), false
- scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
- start := 0
- for start < len(data) {
- r, width := utf8.DecodeRune(data[start:])
- if r == '\n' {
- return start + width, data[start : start+width], nil
- }
- if !unicode.IsSpace(r) {
- break
- }
- start += width
- }
- for i := start; i < len(data); {
- r, width := utf8.DecodeRune(data[i:])
- if r == '\n' {
- return i, data[start:i], nil
- }
- if unicode.IsSpace(r) {
- return i + width, data[start:i], nil
- }
- i += width
- }
- if atEOF && len(data) > start {
- return len(data), data[start:], nil
- }
- return start, nil, nil
- })
- for !returned && scanner.Scan() {
- // for _, v := range stack {
- // fmt.Println(v.val)
- // }
- // fmt.Println()
- s := scanner.Text()
- if s == "\n" {
- continue
- }
- if s[0] == ':' {
- leading := len(s) - len(strings.TrimLeft(s, ":"))
- val := toValue(value{val: `"` + s[leading:]})
- for i := 0; i < leading; i++ {
- val = opThing(val)
- }
- stack = append(stack, val)
- } else if s[0] == '[' {
- list, bracketCnt := []string{}, 0
- for {
- leading := len(s) - len(strings.TrimLeft(s, "["))
- trailing := len(s) - len(strings.TrimRight(s, "]"))
- escape := len(s) - len(strings.TrimRight(strings.TrimRight(s, "]"), "\\")) - trailing
- trailing -= escape & 1
- s = s[leading : len(s)-trailing]
- for i := 0; i < leading; i++ {
- list = append(list, "[")
- }
- if s != "" {
- list = append(list, s)
- }
- for i := 0; i < trailing; i++ {
- list = append(list, "]")
- }
- bracketCnt += leading - trailing
- if bracketCnt < 0 {
- panic(fmt.Errorf("list: %s", errUnmatchedBracket))
- }
- if bracketCnt == 0 {
- break
- }
- s = "\n"
- for s == "\n" && scanner.Scan() {
- s = scanner.Text()
- }
- if s == "\n" {
- panic(fmt.Errorf("list: %s", errUnmatchedBracket))
- }
- }
- stack = append(stack, value{val: strings.Join(list, " ")})
- } else if s[0] >= '0' && s[0] <= '9' || s[0] == '-' {
- toNumber(s)
- stack = append(stack, value{val: s})
- } else {
- stack = append(stack, value{val: s})
- }
- for !returned {
- updated := false
- for i := len(stack) - 1; i >= stackTop; i-- {
- if !isNameWithIndex(`"` + stack[i].val) {
- continue
- }
- paramCnt, ok := reserved[stack[i].val]
- if ok {
- if paramCnt == len(stack)-1-i {
- for j := i + 1; j < len(stack); j++ {
- stack[j] = toValue(stack[j])
- }
- switch stack[i].val {
- case "make":
- stack[i] = opMake(stack[i+1], stack[i+2])
- case "thing":
- stack[i] = opThing(stack[i+1])
- case "print":
- stack[i] = opPrint(stack[i+1])
- case "read":
- stack[i] = opRead(scanner)
- case "add":
- stack[i] = opAdd(stack[i+1], stack[i+2])
- case "sub":
- stack[i] = opSub(stack[i+1], stack[i+2])
- case "mul":
- stack[i] = opMul(stack[i+1], stack[i+2])
- case "div":
- stack[i] = opDiv(stack[i+1], stack[i+2])
- case "mod":
- stack[i] = opMod(stack[i+1], stack[i+2])
- case "erase":
- stack[i] = opErase(stack[i+1])
- case "isname":
- stack[i] = opIsName(stack[i+1])
- case "run":
- stack[i], returned = opRun(stack[i+1])
- case "eq":
- stack[i] = opEq(stack[i+1], stack[i+2])
- case "gt":
- stack[i] = opGt(stack[i+1], stack[i+2])
- case "lt":
- stack[i] = opLt(stack[i+1], stack[i+2])
- case "and":
- stack[i] = opAnd(stack[i+1], stack[i+2])
- case "or":
- stack[i] = opOr(stack[i+1], stack[i+2])
- case "not":
- stack[i] = opNot(stack[i+1])
- case "if":
- stack[i], returned = opIf(stack[i+1], stack[i+2], stack[i+3])
- case "isnumber":
- stack[i] = opIsNumber(stack[i+1])
- case "isword":
- stack[i] = opIsWord(stack[i+1])
- case "islist":
- stack[i] = opIsList(stack[i+1])
- case "isbool":
- stack[i] = opIsBool(stack[i+1])
- case "isempty":
- stack[i] = opIsEmpty(stack[i+1])
- case "return":
- stack[i], returned = stack[i+1], true
- case "export":
- stack[i] = opExport(stack[i+1])
- case "readlist":
- stack[i] = opReadList(scanner)
- case "word":
- stack[i] = opWord(stack[i+1], stack[i+2])
- case "sentence":
- stack[i] = opSentence(stack[i+1], stack[i+2])
- case "list":
- stack[i] = opList(stack[i+1], stack[i+2])
- case "join":
- stack[i] = opJoin(stack[i+1], stack[i+2])
- case "first":
- stack[i] = opFirst(stack[i+1])
- case "last":
- stack[i] = opLast(stack[i+1])
- case "butfirst":
- stack[i] = opButFirst(stack[i+1])
- case "butlast":
- stack[i] = opButLast(stack[i+1])
- case "random":
- stack[i] = opRandom(stack[i+1])
- case "int":
- stack[i] = opInt(stack[i+1])
- case "sqrt":
- stack[i] = opSqrt(stack[i+1])
- case "save":
- stack[i] = opSave(stack[i+1])
- case "load":
- stack[i] = opLoad(stack[i+1])
- case "erall":
- stack[i] = opErAll()
- case "poall":
- stack[i] = opPoAll()
- }
- stack = stack[:i+1]
- updated = true
- }
- break
- }
- val, _ := getValue(`"` + stack[i].val)
- if val.param != nil {
- if len(val.param) == len(stack)-1-i {
- for j := i + 1; j < len(stack); j++ {
- stack[j] = toValue(stack[j])
- }
- local := environ{stack[i].val: val}
- for j, name := range val.param {
- local[name] = stack[i+1+j]
- }
- env = append(env, val.env, local)
- stack[i], _ = opRun(value{val: val.list[1]})
- env = env[:len(env)-2]
- stack = stack[:i+1]
- updated = true
- }
- break
- }
- }
- if !updated {
- break
- }
- }
- }
- if len(stack) == stackTop {
- stack = append(stack, value{val: "[ ]"})
- }
- val = toValue(stack[len(stack)-1])
- stack = stack[:stackTop]
- return
- }
- func main() {
- rand.Seed(time.Now().UnixNano())
- env = append(env, nil, map[string]value{"pi": {val: "3.14159"}})
- if len(os.Args) > 1 {
- file, err := os.Open(os.Args[1])
- if err != nil {
- panic(fmt.Errorf("mua: %s (%s)", errFileError, os.Args[1]))
- }
- os.Stdin = file
- }
- scanner := bufio.NewScanner(os.Stdin)
- interpret(scanner)
- }
|