package main import ( "fmt" "strconv" "strings" ) type expression interface{} type IOHandle struct { Obj expression Open bool Kind string } func (i IOHandle) String() string { state := "CLOSED" if i.Open { state = "OPEN" } return fmt.Sprintf("[%s] io-handle: %s", state, i.Kind) } type number float64 type symbol string type exception string func Parse(s string) expression { tokens := Tokenize(s) expressions := SplitExpressions(tokens) out := make([]expression, 0, len(expressions)) for i := range expressions { out = append(out, parserRead(&expressions[i])) } return out } func SplitExpressions(t []string) [][]string { counter := 0 start := 0 out := make([][]string, 0) for i := range t { if counter < 0 { panic("Too many closing parens found during parsing") } switch t[i] { case "(": if counter == 0 { start = i } counter++ case ")": counter-- if counter == 0 { out = append(out, t[start:i+1]) } default: if counter == 0 { out = append(out, []string{t[i]}) } } } return out } func parserRead(tokens *[]string) expression { token := (*tokens)[0] *tokens = (*tokens)[1:] switch token { case "(": // parse a list expression list := make([]expression, 0) for (*tokens)[0] != ")" { if t := parserRead(tokens); t != symbol("") { list = append(list, t) } } *tokens = (*tokens)[1:] return list default: // parse an atomic value if strings.HasPrefix(token, "0x") { i, err := strconv.ParseInt(token[2:], 16, 0) if err == nil { return number(i) } } if strings.HasPrefix(token, "0") { i, err := strconv.ParseInt(token, 8, 0) if err == nil { return number(i) } } f, err := strconv.ParseFloat(token, 64) if err == nil { return number(f) } if strings.HasPrefix(token, "\"") && strings.HasSuffix(token, "\"") { return unescapeString(token[1 : len(token)-1]) } else if strings.HasPrefix(token, "`") && strings.HasSuffix(token, "`") { return token[1 : len(token)-1] } else if token == "#t" { return true } else if token == "#f" { return false } else { return symbol(token) } } }