slope/parser.go

116 lines
2.1 KiB
Go

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)
}
}
}