forked from slope-lang/slope
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
2.0 KiB
114 lines
2.0 KiB
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 token[1 : len(token)-1]
|
|
} else if token == "#t" {
|
|
return true
|
|
} else if token == "#f" {
|
|
return false
|
|
} else {
|
|
return symbol(token)
|
|
}
|
|
}
|
|
}
|