all: make a ton of features work

This commit is contained in:
2018-05-14 20:59:24 +02:00
parent 8cb7c37096
commit e3334b9ef0
6 changed files with 919 additions and 514 deletions

View File

@@ -1,44 +1,155 @@
package ast
import (
"fmt"
"strings"
"fmt"
"strings"
)
type AST struct {
Tag Tag
Val interface{}
Tag Tag
Val interface{}
}
type Tag int8
const (
Symbol Tag = iota
List
String
Num
Bool
Symbol Tag = iota
List
String
Num
Bool
Fn
Char
Table
Prim
Quoted
)
func (tag Tag) String() string {
names := []string{
"Symbol",
"List",
"String",
"Num",
"Bool",
}
names := []string{
"Symbol",
"List",
"String",
"Num",
"Bool",
"Fn",
"Char",
"Table",
"Prim",
"Quoted",
}
return names[tag]
return names[tag]
}
func (ast AST) Pretty() string {
if ast.Tag == List {
var agg []string
for _, elem := range(ast.Val.([]AST)) {
agg = append(agg, elem.Pretty())
}
return "(" + strings.Join(agg, " ") + ")"
func (ast *AST) Type() *AST {
names := []string{
"sym",
"cons",
"string",
"num",
"bool",
"fn",
"char",
"table",
"fn",
"cons",
}
if ast.Tag == Quoted {
return ast.Val.(*AST).Type()
}
return fmt.Sprintf("%v", ast.Val)
name := names[ast.Tag]
if ast.Tag == Num {
val := ast.Val.(float64)
if val == float64(int64(val)) {
name = "int"
}
}
res := AST{Symbol, name}
return &res
}
func (ast *AST) Pretty() string {
if ast.Tag == List {
var agg []string
for _, elem := range ast.Val.([]*AST) {
agg = append(agg, elem.Pretty())
}
return "(" + strings.Join(agg, " ") + ")"
} else if ast.Tag == Quoted {
return "'" + ast.Val.(*AST).Pretty()
} else if ast.Tag == Fn {
val := ast.Val.(Func)
var agg []string
for _, elem := range val.Params {
agg = append(agg, elem)
}
opt := ""
if val.HasOpt() {
opt = " . " + *val.Opt
}
body := val.Body.Pretty()
return "(fn (" + strings.Join(agg, " ") + opt + ") " + body + ")"
} else if ast.Tag == Char {
return "#" + string(ast.Val.(rune))
} else if ast.Tag == Table {
var agg []string
for k, v := range ast.Val.(map[*AST]*AST) {
agg = append(agg, "("+k.Pretty()+" . "+v.Pretty()+")")
}
return "#hash(" + strings.Join(agg, " ") + ")"
} else if ast.Tag == Prim {
return "#<procedure: " + ast.Val.(Primitive).Name + ">"
}
return fmt.Sprintf("%v", ast.Val)
}
type Env struct {
parent *Env
Values map[string]*AST
}
type PrimFn func([]*AST) (*AST, error)
type Primitive struct {
Name string
Fn PrimFn
}
func newEnv(parent *Env) Env {
return Env{parent, make(map[string]*AST)}
}
func ParentEnv() Env {
return newEnv(nil)
}
func (e *Env) Lookup(elem string) (*AST, error) {
res, ok := e.Values[elem]
if !ok {
if e.parent == nil {
return nil, fmt.Errorf("Symbol not found: %s", elem)
}
return e.parent.Lookup(elem)
}
return res, nil
}
type Func struct {
Params []string
Opt *string
Body *AST
Env Env
}
func (f *Func) HasOpt() bool {
return f.Opt != nil
}