|
@@ -7,8 +7,6 @@ import (
|
|
|
"os"
|
|
"os"
|
|
|
"strings"
|
|
"strings"
|
|
|
"time"
|
|
"time"
|
|
|
- "unicode"
|
|
|
|
|
- "unicode/utf8"
|
|
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
var reserved = map[string]int{
|
|
var reserved = map[string]int{
|
|
@@ -24,58 +22,35 @@ var reserved = map[string]int{
|
|
|
|
|
|
|
|
type environ map[string]value
|
|
type environ map[string]value
|
|
|
type value struct {
|
|
type value struct {
|
|
|
- val string
|
|
|
|
|
|
|
+ tp int
|
|
|
|
|
+ num float64
|
|
|
|
|
+ word string
|
|
|
list []string
|
|
list []string
|
|
|
|
|
+ split []string
|
|
|
param []string
|
|
param []string
|
|
|
|
|
+ body []string
|
|
|
env environ
|
|
env environ
|
|
|
|
|
+ b bool
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-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
|
|
|
|
|
- })
|
|
|
|
|
|
|
+func interpret(scanner *scanProvider, envs []environ) (val value, returned bool) {
|
|
|
|
|
+ stack, returned := []value{}, false
|
|
|
for !returned && scanner.Scan() {
|
|
for !returned && scanner.Scan() {
|
|
|
// for _, v := range stack {
|
|
// for _, v := range stack {
|
|
|
- // fmt.Println(v.val)
|
|
|
|
|
|
|
+ // fmt.Println(toString(v))
|
|
|
// }
|
|
// }
|
|
|
// fmt.Println()
|
|
// fmt.Println()
|
|
|
|
|
+ // fmt.Println(envs[0])
|
|
|
|
|
+ // fmt.Println()
|
|
|
s := scanner.Text()
|
|
s := scanner.Text()
|
|
|
if s == "\n" {
|
|
if s == "\n" {
|
|
|
continue
|
|
continue
|
|
|
}
|
|
}
|
|
|
if s[0] == ':' {
|
|
if s[0] == ':' {
|
|
|
leading := len(s) - len(strings.TrimLeft(s, ":"))
|
|
leading := len(s) - len(strings.TrimLeft(s, ":"))
|
|
|
- val := toValue(value{val: `"` + s[leading:]})
|
|
|
|
|
|
|
+ val := toValue(value{word: `"` + s[leading:]}, envs[0])
|
|
|
for i := 0; i < leading; i++ {
|
|
for i := 0; i < leading; i++ {
|
|
|
- val = opThing(val)
|
|
|
|
|
|
|
+ val = toValue(opThing(val, envs), envs[0])
|
|
|
}
|
|
}
|
|
|
stack = append(stack, val)
|
|
stack = append(stack, val)
|
|
|
} else if s[0] == '[' {
|
|
} else if s[0] == '[' {
|
|
@@ -83,7 +58,7 @@ func interpret(scanner *bufio.Scanner) (val value, returned bool) {
|
|
|
for {
|
|
for {
|
|
|
leading := len(s) - len(strings.TrimLeft(s, "["))
|
|
leading := len(s) - len(strings.TrimLeft(s, "["))
|
|
|
trailing := len(s) - len(strings.TrimRight(s, "]"))
|
|
trailing := len(s) - len(strings.TrimRight(s, "]"))
|
|
|
- escape := len(s) - len(strings.TrimRight(strings.TrimRight(s, "]"), "\\")) - trailing
|
|
|
|
|
|
|
+ escape := len(s) - len(strings.TrimRight(strings.TrimRight(s, "]"), `\`)) - trailing
|
|
|
trailing -= escape & 1
|
|
trailing -= escape & 1
|
|
|
s = s[leading : len(s)-trailing]
|
|
s = s[leading : len(s)-trailing]
|
|
|
for i := 0; i < leading; i++ {
|
|
for i := 0; i < leading; i++ {
|
|
@@ -110,133 +85,128 @@ func interpret(scanner *bufio.Scanner) (val value, returned bool) {
|
|
|
panic(fmt.Errorf("list: %s", errUnmatchedBracket))
|
|
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})
|
|
|
|
|
|
|
+ stack = append(stack, value{word: strings.Join(list, " ")})
|
|
|
} else {
|
|
} else {
|
|
|
- stack = append(stack, value{val: s})
|
|
|
|
|
|
|
+ stack = append(stack, value{word: s})
|
|
|
}
|
|
}
|
|
|
for !returned {
|
|
for !returned {
|
|
|
updated := false
|
|
updated := false
|
|
|
- for i := len(stack) - 1; i >= stackTop; i-- {
|
|
|
|
|
- if !isNameWithIndex(`"` + stack[i].val) {
|
|
|
|
|
|
|
+ for i := len(stack) - 1; i >= 0; i-- {
|
|
|
|
|
+ if !isName(value{word: `"` + stack[i].word}) {
|
|
|
continue
|
|
continue
|
|
|
}
|
|
}
|
|
|
- paramCnt, ok := reserved[stack[i].val]
|
|
|
|
|
|
|
+ paramCnt, ok := reserved[stack[i].word]
|
|
|
if ok {
|
|
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
|
|
|
|
|
|
|
+ if paramCnt > len(stack)-1-i {
|
|
|
|
|
+ break
|
|
|
}
|
|
}
|
|
|
- break
|
|
|
|
|
|
|
+ for j := i + 1; j < len(stack); j++ {
|
|
|
|
|
+ stack[j] = toValue(stack[j], envs[0])
|
|
|
|
|
+ }
|
|
|
|
|
+ switch stack[i].word {
|
|
|
|
|
+ case "make":
|
|
|
|
|
+ stack[i] = opMake(stack[i+1], stack[i+2], envs)
|
|
|
|
|
+ case "thing":
|
|
|
|
|
+ stack[i] = opThing(stack[i+1], envs)
|
|
|
|
|
+ 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], envs)
|
|
|
|
|
+ case "isname":
|
|
|
|
|
+ stack[i] = opIsName(stack[i+1])
|
|
|
|
|
+ case "run":
|
|
|
|
|
+ stack[i], returned = opRun(stack[i+1], envs)
|
|
|
|
|
+ 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], envs)
|
|
|
|
|
+ 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], envs)
|
|
|
|
|
+ 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], envs[0])
|
|
|
|
|
+ case "load":
|
|
|
|
|
+ stack[i] = opLoad(stack[i+1], envs[0])
|
|
|
|
|
+ case "erall":
|
|
|
|
|
+ stack[i] = opErAll(envs[0])
|
|
|
|
|
+ case "poall":
|
|
|
|
|
+ stack[i] = opPoAll(envs[0])
|
|
|
|
|
+ }
|
|
|
|
|
+ stack = stack[:i+1]
|
|
|
|
|
+ updated = true
|
|
|
}
|
|
}
|
|
|
- val, _ := getValue(`"` + stack[i].val)
|
|
|
|
|
|
|
+ val, _ := getValue(`"`+stack[i].word, envs)
|
|
|
if val.param != nil {
|
|
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
|
|
|
|
|
|
|
+ if len(val.param) > len(stack)-1-i {
|
|
|
|
|
+ break
|
|
|
}
|
|
}
|
|
|
- break
|
|
|
|
|
|
|
+ for j := i + 1; j < len(stack); j++ {
|
|
|
|
|
+ stack[j] = toValue(stack[j], envs[0])
|
|
|
|
|
+ }
|
|
|
|
|
+ local := environ{stack[i].word: val}
|
|
|
|
|
+ for j, name := range val.param {
|
|
|
|
|
+ local[name] = stack[i+1+j]
|
|
|
|
|
+ }
|
|
|
|
|
+ stack[i], _ = opRun(value{tp: typeList, split: val.body}, []environ{local, val.env, envs[2]})
|
|
|
|
|
+ stack = stack[:i+1]
|
|
|
|
|
+ updated = true
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
if !updated {
|
|
if !updated {
|
|
@@ -244,26 +214,25 @@ func interpret(scanner *bufio.Scanner) (val value, returned bool) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- if len(stack) == stackTop {
|
|
|
|
|
- stack = append(stack, value{val: "[ ]"})
|
|
|
|
|
|
|
+ if len(stack) == 0 {
|
|
|
|
|
+ val = value{tp: typeList, list: []string{}, split: []string{"[", "]"}}
|
|
|
|
|
+ return
|
|
|
}
|
|
}
|
|
|
- val = toValue(stack[len(stack)-1])
|
|
|
|
|
- stack = stack[:stackTop]
|
|
|
|
|
|
|
+ val = toValue(stack[len(stack)-1], envs[0])
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
func main() {
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
- env = append(env, nil, map[string]value{"pi": {val: "3.14159"}})
|
|
|
|
|
-
|
|
|
|
|
|
|
+ env := map[string]value{"pi": {tp: typeNumber, num: 3.14159}}
|
|
|
if len(os.Args) > 1 {
|
|
if len(os.Args) > 1 {
|
|
|
file, err := os.Open(os.Args[1])
|
|
file, err := os.Open(os.Args[1])
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- panic(fmt.Errorf("mua: %s (%s)", errFileError, os.Args[1]))
|
|
|
|
|
|
|
+ panic(fmt.Errorf("script: %s (%s)", errFileError, os.Args[1]))
|
|
|
}
|
|
}
|
|
|
os.Stdin = file
|
|
os.Stdin = file
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
|
- interpret(scanner)
|
|
|
|
|
|
|
+ scanner.Split(splitFunc)
|
|
|
|
|
+ interpret(&scanProvider{isList: false, scanner: scanner}, []environ{env, nil, env})
|
|
|
}
|
|
}
|