Let
This commit is contained in:
parent
7c40723537
commit
8f5b16878f
4 changed files with 316 additions and 144 deletions
7
input.go
7
input.go
|
|
@ -28,10 +28,13 @@ func (in *Input) Peek(i int) Lexeme {
|
||||||
return in.input[in.index+i]
|
return in.input[in.index+i]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *Input) Pop() Lexeme {
|
func (in *Input) Pop() (Lexeme, bool) {
|
||||||
|
if in.index > len(in.input)-1 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
v := in.input[in.index]
|
v := in.input[in.index]
|
||||||
in.index++
|
in.index++
|
||||||
return v
|
return v, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *Input) Seek(i int) {
|
func (in *Input) Seek(i int) {
|
||||||
|
|
|
||||||
30
lex.go
30
lex.go
|
|
@ -39,6 +39,8 @@ type Token token[string]
|
||||||
|
|
||||||
type Int token[int]
|
type Int token[int]
|
||||||
|
|
||||||
|
type Float token[float64]
|
||||||
|
|
||||||
type Identifier token[Id]
|
type Identifier token[Id]
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -84,9 +86,8 @@ func (t *Token) Equals(a Lexeme) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Int) Equals(a Lexeme) bool {
|
func (t *Int) Equals(a Lexeme) bool { return false }
|
||||||
return false
|
func (t *Float) Equals(a Lexeme) bool { return false }
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Identifier) Equals(a Lexeme) bool {
|
func (t *Identifier) Equals(a Lexeme) bool {
|
||||||
switch x := a.(type) {
|
switch x := a.(type) {
|
||||||
|
|
@ -97,17 +98,18 @@ func (t *Identifier) Equals(a Lexeme) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var matchNumbers = regexp.MustCompile(`-?\d+`)
|
var matchInt = regexp.MustCompile(`-?\d+`)
|
||||||
|
var matchFloat = regexp.MustCompile(`-?\d+\.\d*`)
|
||||||
var matchIdentifier = regexp.MustCompile(`[^\'() ]+`)
|
var matchIdentifier = regexp.MustCompile(`[^\'() ]+`)
|
||||||
|
|
||||||
func lex(source string) (*Input, error) {
|
func lex(source string) (*Input, error) {
|
||||||
var (
|
var (
|
||||||
pos, line, column int
|
pos, line, column int = 1, 1, 1
|
||||||
tokens []Lexeme
|
tokens []Lexeme
|
||||||
)
|
)
|
||||||
outer:
|
outer:
|
||||||
for len(source) > 0 {
|
for len(source) > 0 {
|
||||||
p := position{pos: pos, line: line, column: column, filepath: "sourceinput"}
|
p := position{pos: pos, line: line, column: column, filepath: "stdin"}
|
||||||
for _, try := range knownTokens {
|
for _, try := range knownTokens {
|
||||||
if !strings.HasPrefix(source, try.value) {
|
if !strings.HasPrefix(source, try.value) {
|
||||||
continue
|
continue
|
||||||
|
|
@ -130,7 +132,21 @@ outer:
|
||||||
}
|
}
|
||||||
continue outer
|
continue outer
|
||||||
}
|
}
|
||||||
index := matchNumbers.FindStringSubmatchIndex(source)
|
index := matchFloat.FindStringSubmatchIndex(source)
|
||||||
|
if index != nil && index[0] == 0 {
|
||||||
|
a := source[index[0]:index[1]]
|
||||||
|
conv, err := strconv.ParseFloat(a, 64)
|
||||||
|
if err == nil {
|
||||||
|
var i = &Float{position: p, value: conv}
|
||||||
|
tokens = append(tokens, i)
|
||||||
|
l := len(a)
|
||||||
|
source = source[l:]
|
||||||
|
column += l
|
||||||
|
pos += l
|
||||||
|
continue outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index = matchInt.FindStringSubmatchIndex(source)
|
||||||
if index != nil && index[0] == 0 {
|
if index != nil && index[0] == 0 {
|
||||||
a := source[index[0]:index[1]]
|
a := source[index[0]:index[1]]
|
||||||
conv, err := strconv.Atoi(a)
|
conv, err := strconv.Atoi(a)
|
||||||
|
|
|
||||||
240
main.go
240
main.go
|
|
@ -1,75 +1,74 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var source = `
|
var source = ""
|
||||||
(+ 1 2 3 4)
|
|
||||||
`
|
|
||||||
|
|
||||||
func (v *Value[T]) Step() (Expression, error) {
|
func (v *Value[T]) Step() (Expression, error) { return v, nil }
|
||||||
return v, nil
|
func (v *Value[T]) Replace(Id, Expression) {}
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Value[T]) Replace(Id, Expression) {
|
func (v *Quoted) Step() (Expression, error) { return v, nil }
|
||||||
}
|
func (v *Quoted) Replace(Id, Expression) {}
|
||||||
|
|
||||||
func (v *Quoted) Step() (Expression, error) {
|
|
||||||
return v, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Quoted) Replace(Id, Expression) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Declaration) Step() (Expression, error) {
|
func (d *Declaration) Step() (Expression, error) {
|
||||||
return &Value[int]{0}, nil
|
for _, v := range d.variables {
|
||||||
|
if isValue(v.expr) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
n, err := v.expr.Step()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
v.expr = n
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
for _, v := range d.variables {
|
||||||
|
for _, b := range d.body {
|
||||||
|
b.Replace(v.id.value, v.expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(d.body) == 0 {
|
||||||
|
return zero, nil
|
||||||
|
}
|
||||||
|
for i, b := range d.body {
|
||||||
|
if isValue(b) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
n, err := b.Step()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
d.body[i] = n
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
return d.body[len(d.body)-1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Declaration) Replace(id Id, expr Expression) {
|
func (d *Declaration) Replace(id Id, expr Expression) {
|
||||||
if id == v.id.value {
|
for _, v := range d.variables {
|
||||||
return
|
v.expr.Replace(id, expr)
|
||||||
} else {
|
}
|
||||||
switch x := v.expr.(type) {
|
for _, b := range d.body {
|
||||||
case *Identifier:
|
b.Replace(id, expr)
|
||||||
if x.value == id {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Symbol) Step() (Expression, error) {
|
||||||
|
if v.expr == nil {
|
||||||
|
return nil, fmt.Errorf("unbound symbol %s at %s", v.id, v.id.position)
|
||||||
|
}
|
||||||
|
return v.expr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Symbol) Replace(id Id, expr Expression) {
|
||||||
|
if v.id.value == id {
|
||||||
v.expr = expr
|
v.expr = expr
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
x.Replace(id, expr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Identifier) Step() (Expression, error) {
|
|
||||||
switch v.value {
|
|
||||||
case "+":
|
|
||||||
f := func(args []Expression) (Expression, error) {
|
|
||||||
sum := 0
|
|
||||||
for _, arg := range args {
|
|
||||||
if !isValue(arg) {
|
|
||||||
panic("!")
|
|
||||||
}
|
|
||||||
switch x := arg.(type) {
|
|
||||||
case *Value[int]:
|
|
||||||
sum += x.value
|
|
||||||
case *Value[*Int]:
|
|
||||||
sum += x.value.value
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("invalid type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &Value[int]{sum}, nil
|
|
||||||
}
|
|
||||||
return &Value[Function]{f}, nil
|
|
||||||
default:
|
|
||||||
panic("!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Identifier) Replace(id Id, expr Expression) {
|
|
||||||
panic("!")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Lambda) Step() (Expression, error) {
|
func (l *Lambda) Step() (Expression, error) {
|
||||||
|
|
@ -78,20 +77,12 @@ func (l *Lambda) Step() (Expression, error) {
|
||||||
return nil, fmt.Errorf("unexpected number of arguments")
|
return nil, fmt.Errorf("unexpected number of arguments")
|
||||||
}
|
}
|
||||||
for i, arg := range l.args {
|
for i, arg := range l.args {
|
||||||
argExpr := args[i]
|
for _, e := range l.body {
|
||||||
for j, e := range l.body {
|
e.Replace(arg.id.value, args[i])
|
||||||
switch x := e.(type) {
|
|
||||||
case *Identifier:
|
|
||||||
if x.value == arg.value {
|
|
||||||
l.body[j] = argExpr
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
e.Replace(arg.value, argExpr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(l.body) == 0 {
|
if len(l.body) == 0 {
|
||||||
return &Value[int]{0}, nil
|
return zero, nil
|
||||||
}
|
}
|
||||||
for i, expr := range l.body {
|
for i, expr := range l.body {
|
||||||
if isValue(expr) {
|
if isValue(expr) {
|
||||||
|
|
@ -109,7 +100,9 @@ func (l *Lambda) Step() (Expression, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Lambda) Replace(id Id, expr Expression) {
|
func (l *Lambda) Replace(id Id, expr Expression) {
|
||||||
panic("!")
|
for _, b := range l.body {
|
||||||
|
b.Replace(id, expr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *List) Step() (Expression, error) {
|
func (v *List) Step() (Expression, error) {
|
||||||
|
|
@ -124,7 +117,7 @@ func (v *List) Step() (Expression, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(v.els) == 0 {
|
if len(v.els) == 0 {
|
||||||
return nil, fmt.Errorf("empty list")
|
return zero, nil
|
||||||
}
|
}
|
||||||
f, ok := v.els[0].(*Value[Function])
|
f, ok := v.els[0].(*Value[Function])
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -138,21 +131,14 @@ func (v *List) Step() (Expression, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *List) Replace(id Id, expr Expression) {
|
func (v *List) Replace(id Id, expr Expression) {
|
||||||
for i, e := range v.els {
|
for _, e := range v.els {
|
||||||
switch x := e.(type) {
|
|
||||||
case *Identifier:
|
|
||||||
if x.value == id {
|
|
||||||
v.els[i] = expr
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
e.Replace(id, expr)
|
e.Replace(id, expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func isValue(e Expression) bool {
|
func isValue(e Expression) bool {
|
||||||
switch e.(type) {
|
switch e.(type) {
|
||||||
case *Value[int], *Value[*Int], *Value[Function], *Quoted:
|
case *Value[int], *Value[float64], *Value[Function], *Quoted:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
|
@ -170,25 +156,101 @@ func fullStep(e Expression) (Expression, error) {
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stdlib(expr Expression) {
|
||||||
|
functions := map[Id]Function{
|
||||||
|
"+": func(args []Expression) (Expression, error) {
|
||||||
|
sum := 0
|
||||||
|
for _, arg := range args {
|
||||||
|
if !isValue(arg) {
|
||||||
|
panic("!")
|
||||||
|
}
|
||||||
|
switch x := arg.(type) {
|
||||||
|
case *Value[int]:
|
||||||
|
sum += x.value
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &Value[int]{sum}, nil
|
||||||
|
},
|
||||||
|
"-": func(args []Expression) (Expression, error) {
|
||||||
|
v0, ok := args[0].(*Value[int])
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("integer value was expected")
|
||||||
|
}
|
||||||
|
v1, ok := args[1].(*Value[int])
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("integer value was expected")
|
||||||
|
}
|
||||||
|
return &Value[int]{v0.value - v1.value}, nil
|
||||||
|
},
|
||||||
|
"*": func(args []Expression) (Expression, error) {
|
||||||
|
v0, ok := args[0].(*Value[int])
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("integer value was expected")
|
||||||
|
}
|
||||||
|
v1, ok := args[1].(*Value[int])
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("integer value was expected")
|
||||||
|
}
|
||||||
|
return &Value[int]{v0.value * v1.value}, nil
|
||||||
|
},
|
||||||
|
"/": func(args []Expression) (Expression, error) {
|
||||||
|
v0, ok := args[0].(*Value[int])
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("integer value was expected")
|
||||||
|
}
|
||||||
|
v1, ok := args[1].(*Value[int])
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("integer value was expected")
|
||||||
|
}
|
||||||
|
return &Value[int]{v0.value / v1.value}, nil
|
||||||
|
},
|
||||||
|
"/.": func(args []Expression) (Expression, error) {
|
||||||
|
v0, ok := args[0].(*Value[float64])
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("float value was expected")
|
||||||
|
}
|
||||||
|
v1, ok := args[1].(*Value[float64])
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("float value was expected")
|
||||||
|
}
|
||||||
|
return &Value[float64]{float64(v0.value) / float64(v1.value)}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for id, f := range functions {
|
||||||
|
expr.Replace(id, &Value[Function]{f})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) > 1 {
|
logger := log.New(os.Stderr, "error: ", 0)
|
||||||
source = os.Args[1]
|
evalString := flag.String("eval", "", "evaluate an expression and return its value")
|
||||||
|
flag.Parse()
|
||||||
|
args := flag.Args()
|
||||||
|
if len(args) > 0 {
|
||||||
|
bytes, err := os.ReadFile(os.Args[1])
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal(fmt.Errorf("file not found"))
|
||||||
|
}
|
||||||
|
source = string(bytes)
|
||||||
|
} else if *evalString != "" {
|
||||||
|
source = *evalString
|
||||||
|
} else {
|
||||||
|
logger.Fatal(fmt.Errorf("missing input file"))
|
||||||
}
|
}
|
||||||
tk, err := lex(source)
|
tk, err := lex(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
logger.Fatal(err)
|
||||||
}
|
}
|
||||||
p, err := consume(tk)
|
p, err := consume(tk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
logger.Fatal(err)
|
||||||
}
|
}
|
||||||
s, err := p.Step()
|
stdlib(p)
|
||||||
|
result, err := fullStep(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
logger.Fatal(err)
|
||||||
}
|
|
||||||
result, err := fullStep(s)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
fmt.Println(result)
|
fmt.Println(result)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
183
parse.go
183
parse.go
|
|
@ -6,22 +6,25 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var noMatch = errors.New("no match")
|
var (
|
||||||
|
noMatch = errors.New("no match")
|
||||||
|
zero = &Value[int]{0}
|
||||||
|
)
|
||||||
|
|
||||||
type Function func([]Expression) (Expression, error)
|
type Function func([]Expression) (Expression, error)
|
||||||
|
|
||||||
type Expression interface {
|
type Expression interface {
|
||||||
Step() (Expression, error)
|
Step() (Expression, error)
|
||||||
Replace(Id, Expression)
|
Replace(Id, Expression)
|
||||||
// Visit(func(Expression) error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type List struct {
|
type List struct {
|
||||||
els []Expression
|
els []Expression
|
||||||
}
|
}
|
||||||
|
|
||||||
type Value[T interface{ *Int | int | Function }] struct {
|
type Value[T interface{ int | float64 | Function }] struct {
|
||||||
value T
|
value T
|
||||||
|
// rng Range
|
||||||
}
|
}
|
||||||
|
|
||||||
type Quoted struct {
|
type Quoted struct {
|
||||||
|
|
@ -29,14 +32,23 @@ type Quoted struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Declaration struct {
|
type Declaration struct {
|
||||||
|
variables []*Symbol
|
||||||
|
body []Expression
|
||||||
|
}
|
||||||
|
|
||||||
|
type Lambda struct {
|
||||||
|
args []*Symbol
|
||||||
|
body []Expression
|
||||||
|
}
|
||||||
|
|
||||||
|
type Symbol struct {
|
||||||
id *Identifier
|
id *Identifier
|
||||||
expr Expression
|
expr Expression
|
||||||
}
|
}
|
||||||
|
|
||||||
type Lambda struct {
|
// type Progn struct {
|
||||||
args []*Identifier
|
// *List
|
||||||
body []Expression
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
func (v Value[T]) String() string {
|
func (v Value[T]) String() string {
|
||||||
return fmt.Sprint(v.value)
|
return fmt.Sprint(v.value)
|
||||||
|
|
@ -54,19 +66,31 @@ func (v List) String() string {
|
||||||
return fmt.Sprintf("(%s)", strings.Join(s, " "))
|
return fmt.Sprintf("(%s)", strings.Join(s, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Lambda) String() string {
|
func (v Lambda) String() string {
|
||||||
// var args = new(List)
|
var args List
|
||||||
// args.els = append(args.els, v.args...)
|
for _, arg := range v.args {
|
||||||
//
|
args.els = append(args.els, arg)
|
||||||
// var s []string
|
}
|
||||||
// for _, e := range v.args {
|
var s []string
|
||||||
// s = append(s, fmt.Sprint(e))
|
for _, e := range v.body {
|
||||||
// }
|
s = append(s, fmt.Sprint(e))
|
||||||
return "fuck you"
|
}
|
||||||
|
return fmt.Sprintf("(lambda %v %v)", &args, strings.Join(s, " "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Function) String() string {
|
||||||
|
return "(lambda (..) (..))"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Symbol) String() string {
|
||||||
|
return fmt.Sprintf("%v", t.id.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseQuotedObject(in *Input) (Expression, error) {
|
func parseQuotedObject(in *Input) (Expression, error) {
|
||||||
l := in.Pop()
|
l, ok := in.Pop()
|
||||||
|
if !ok {
|
||||||
|
return nil, noMatch
|
||||||
|
}
|
||||||
switch {
|
switch {
|
||||||
case l.Equals(SingleQuote):
|
case l.Equals(SingleQuote):
|
||||||
n, err := consume(in)
|
n, err := consume(in)
|
||||||
|
|
@ -80,27 +104,38 @@ func parseQuotedObject(in *Input) (Expression, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSymbol(in *Input) (Expression, error) {
|
func parseSymbol(in *Input) (Expression, error) {
|
||||||
l := in.Pop()
|
l, ok := in.Pop()
|
||||||
|
if !ok {
|
||||||
|
return nil, noMatch
|
||||||
|
}
|
||||||
switch x := l.(type) {
|
switch x := l.(type) {
|
||||||
case *Identifier:
|
case *Identifier:
|
||||||
return x, nil
|
return &Symbol{id: x}, nil
|
||||||
default:
|
default:
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseValue(in *Input) (Expression, error) {
|
func parseValue(in *Input) (Expression, error) {
|
||||||
l := in.Pop()
|
l, ok := in.Pop()
|
||||||
|
if !ok {
|
||||||
|
return nil, noMatch
|
||||||
|
}
|
||||||
switch x := l.(type) {
|
switch x := l.(type) {
|
||||||
case *Int:
|
case *Int:
|
||||||
return &Value[*Int]{x}, nil
|
return &Value[int]{x.value}, nil
|
||||||
|
case *Float:
|
||||||
|
return &Value[float64]{x.value}, nil
|
||||||
default:
|
default:
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseList(in *Input) (Expression, error) {
|
func parseList(in *Input) (Expression, error) {
|
||||||
openingParens := in.Pop()
|
openingParens, ok := in.Pop()
|
||||||
|
if !ok {
|
||||||
|
return nil, noMatch
|
||||||
|
}
|
||||||
if !openingParens.Equals(Lparen) {
|
if !openingParens.Equals(Lparen) {
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
|
|
@ -117,28 +152,18 @@ func parseList(in *Input) (Expression, error) {
|
||||||
}
|
}
|
||||||
args.els = append(args.els, arg)
|
args.els = append(args.els, arg)
|
||||||
}
|
}
|
||||||
_ = in.Pop()
|
_, ok = in.Pop()
|
||||||
|
if !ok {
|
||||||
|
return nil, noMatch
|
||||||
|
}
|
||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseLet(in *Input) (Expression, error) {
|
func parseLet(in *Input) (Expression, error) {
|
||||||
token := in.Pop()
|
openingParens, ok := in.Pop()
|
||||||
if !token.Equals(Let) {
|
|
||||||
return nil, noMatch
|
|
||||||
}
|
|
||||||
id, ok := in.Pop().(*Identifier)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
expr, err := consume(in)
|
|
||||||
if err != nil {
|
|
||||||
return nil, noMatch
|
|
||||||
}
|
|
||||||
return &Declaration{id: id, expr: expr}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseLambda(in *Input) (Expression, error) {
|
|
||||||
openingParens := in.Pop()
|
|
||||||
if !openingParens.Equals(Lparen) {
|
if !openingParens.Equals(Lparen) {
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
|
|
@ -147,7 +172,61 @@ func parseLambda(in *Input) (Expression, error) {
|
||||||
return nil, fmt.Errorf("unmatched parenthesis starting at %s", openingParens.Position())
|
return nil, fmt.Errorf("unmatched parenthesis starting at %s", openingParens.Position())
|
||||||
}
|
}
|
||||||
decl := in.Take(idx)
|
decl := in.Take(idx)
|
||||||
tok := decl.Pop()
|
tok, ok := decl.Pop()
|
||||||
|
if !ok {
|
||||||
|
return nil, noMatch
|
||||||
|
}
|
||||||
|
if !tok.Equals(Let) {
|
||||||
|
return nil, noMatch
|
||||||
|
}
|
||||||
|
l, err := parseList(decl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
list, ok := l.(*List)
|
||||||
|
if !ok {
|
||||||
|
return nil, noMatch
|
||||||
|
}
|
||||||
|
var variables []*Symbol
|
||||||
|
for _, e := range list.els {
|
||||||
|
l, ok := e.(*List)
|
||||||
|
if !ok {
|
||||||
|
return nil, noMatch
|
||||||
|
}
|
||||||
|
if len(l.els) != 2 {
|
||||||
|
return nil, noMatch
|
||||||
|
}
|
||||||
|
d, ok := l.els[0].(*Symbol)
|
||||||
|
if !ok {
|
||||||
|
return nil, noMatch
|
||||||
|
}
|
||||||
|
d.expr = l.els[1]
|
||||||
|
variables = append(variables, d)
|
||||||
|
}
|
||||||
|
body, err := consumeAll(decl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Declaration{variables: variables, body: body}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseLambda(in *Input) (Expression, error) {
|
||||||
|
openingParens, ok := in.Pop()
|
||||||
|
if !ok {
|
||||||
|
return nil, noMatch
|
||||||
|
}
|
||||||
|
if !openingParens.Equals(Lparen) {
|
||||||
|
return nil, noMatch
|
||||||
|
}
|
||||||
|
idx, ok := in.Find(Lparen, Rparen)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unmatched parenthesis starting at %s", openingParens.Position())
|
||||||
|
}
|
||||||
|
decl := in.Take(idx)
|
||||||
|
tok, ok := decl.Pop()
|
||||||
|
if !ok {
|
||||||
|
return nil, noMatch
|
||||||
|
}
|
||||||
if !tok.Equals(LambdaTok) {
|
if !tok.Equals(LambdaTok) {
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
|
|
@ -159,23 +238,22 @@ func parseLambda(in *Input) (Expression, error) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
var args []*Identifier
|
var args []*Symbol
|
||||||
for _, e := range list.els {
|
for _, e := range list.els {
|
||||||
id, ok := e.(*Identifier)
|
id, ok := e.(*Symbol)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
args = append(args, id)
|
args = append(args, id)
|
||||||
}
|
}
|
||||||
var body []Expression
|
body, err := consumeAll(decl)
|
||||||
for decl.Len() > 0 {
|
|
||||||
n, err := consume(decl)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
body = append(body, n)
|
_, ok = in.Pop()
|
||||||
|
if !ok {
|
||||||
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
_ = in.Pop()
|
|
||||||
return &Lambda{args: args, body: body}, nil
|
return &Lambda{args: args, body: body}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,10 +263,10 @@ func consume(in *Input) (n Expression, err error) {
|
||||||
var parseFunctions = []ParserFunc{
|
var parseFunctions = []ParserFunc{
|
||||||
parseQuotedObject,
|
parseQuotedObject,
|
||||||
parseLambda,
|
parseLambda,
|
||||||
|
parseLet,
|
||||||
parseList,
|
parseList,
|
||||||
parseSymbol,
|
parseSymbol,
|
||||||
parseValue,
|
parseValue,
|
||||||
parseLet,
|
|
||||||
}
|
}
|
||||||
for _, f := range parseFunctions {
|
for _, f := range parseFunctions {
|
||||||
start := in.Index()
|
start := in.Index()
|
||||||
|
|
@ -205,3 +283,16 @@ func consume(in *Input) (n Expression, err error) {
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unrecognized construction: %s", in)
|
return nil, fmt.Errorf("unrecognized construction: %s", in)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func consumeAll(in *Input) (e []Expression, err error) {
|
||||||
|
for in.Len() > 0 {
|
||||||
|
start := in.Index()
|
||||||
|
n, err := consume(in)
|
||||||
|
if err != nil {
|
||||||
|
in.Seek(start)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
e = append(e, n)
|
||||||
|
}
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue