Let
This commit is contained in:
parent
7c40723537
commit
8f5b16878f
4 changed files with 316 additions and 144 deletions
234
main.go
234
main.go
|
|
@ -1,75 +1,74 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
var source = `
|
||||
(+ 1 2 3 4)
|
||||
`
|
||||
var source = ""
|
||||
|
||||
func (v *Value[T]) Step() (Expression, error) {
|
||||
return v, nil
|
||||
}
|
||||
func (v *Value[T]) Step() (Expression, error) { 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) {
|
||||
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) {
|
||||
if id == v.id.value {
|
||||
return
|
||||
} else {
|
||||
switch x := v.expr.(type) {
|
||||
case *Identifier:
|
||||
if x.value == id {
|
||||
v.expr = expr
|
||||
}
|
||||
default:
|
||||
x.Replace(id, expr)
|
||||
}
|
||||
func (d *Declaration) Replace(id Id, expr Expression) {
|
||||
for _, v := range d.variables {
|
||||
v.expr.Replace(id, expr)
|
||||
}
|
||||
for _, b := range d.body {
|
||||
b.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 *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 *Identifier) Replace(id Id, expr Expression) {
|
||||
panic("!")
|
||||
func (v *Symbol) Replace(id Id, expr Expression) {
|
||||
if v.id.value == id {
|
||||
v.expr = expr
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Lambda) Step() (Expression, error) {
|
||||
|
|
@ -78,20 +77,12 @@ func (l *Lambda) Step() (Expression, error) {
|
|||
return nil, fmt.Errorf("unexpected number of arguments")
|
||||
}
|
||||
for i, arg := range l.args {
|
||||
argExpr := args[i]
|
||||
for j, e := range l.body {
|
||||
switch x := e.(type) {
|
||||
case *Identifier:
|
||||
if x.value == arg.value {
|
||||
l.body[j] = argExpr
|
||||
}
|
||||
default:
|
||||
e.Replace(arg.value, argExpr)
|
||||
}
|
||||
for _, e := range l.body {
|
||||
e.Replace(arg.id.value, args[i])
|
||||
}
|
||||
}
|
||||
if len(l.body) == 0 {
|
||||
return &Value[int]{0}, nil
|
||||
return zero, nil
|
||||
}
|
||||
for i, expr := range l.body {
|
||||
if isValue(expr) {
|
||||
|
|
@ -109,7 +100,9 @@ func (l *Lambda) Step() (Expression, error) {
|
|||
}
|
||||
|
||||
func (l *Lambda) Replace(id Id, expr Expression) {
|
||||
panic("!")
|
||||
for _, b := range l.body {
|
||||
b.Replace(id, expr)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *List) Step() (Expression, error) {
|
||||
|
|
@ -124,7 +117,7 @@ func (v *List) Step() (Expression, error) {
|
|||
}
|
||||
}
|
||||
if len(v.els) == 0 {
|
||||
return nil, fmt.Errorf("empty list")
|
||||
return zero, nil
|
||||
}
|
||||
f, ok := v.els[0].(*Value[Function])
|
||||
if !ok {
|
||||
|
|
@ -138,21 +131,14 @@ func (v *List) Step() (Expression, error) {
|
|||
}
|
||||
|
||||
func (v *List) Replace(id Id, expr Expression) {
|
||||
for i, e := range v.els {
|
||||
switch x := e.(type) {
|
||||
case *Identifier:
|
||||
if x.value == id {
|
||||
v.els[i] = expr
|
||||
}
|
||||
default:
|
||||
e.Replace(id, expr)
|
||||
}
|
||||
for _, e := range v.els {
|
||||
e.Replace(id, expr)
|
||||
}
|
||||
}
|
||||
|
||||
func isValue(e Expression) bool {
|
||||
switch e.(type) {
|
||||
case *Value[int], *Value[*Int], *Value[Function], *Quoted:
|
||||
case *Value[int], *Value[float64], *Value[Function], *Quoted:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
|
|
@ -170,25 +156,101 @@ func fullStep(e Expression) (Expression, error) {
|
|||
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() {
|
||||
if len(os.Args) > 1 {
|
||||
source = os.Args[1]
|
||||
logger := log.New(os.Stderr, "error: ", 0)
|
||||
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)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
logger.Fatal(err)
|
||||
}
|
||||
p, err := consume(tk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
logger.Fatal(err)
|
||||
}
|
||||
s, err := p.Step()
|
||||
stdlib(p)
|
||||
result, err := fullStep(p)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
result, err := fullStep(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
logger.Fatal(err)
|
||||
}
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue