134 lines
2.5 KiB
Go
134 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"reflect"
|
|
)
|
|
|
|
var source = ""
|
|
|
|
func isValue(e Expression) bool {
|
|
_, ok := e.(Value)
|
|
return ok
|
|
}
|
|
|
|
func fullStep(e Expression) (Expression, error) {
|
|
for !isValue(e) {
|
|
n, err := e.Step()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
e = n
|
|
}
|
|
return e, nil
|
|
}
|
|
|
|
func builtinFunctions(expr Expression) {
|
|
functions := map[Id]BuiltInFunction{
|
|
"+.": {
|
|
t: &FunctionType{
|
|
ret: &PrimFloat,
|
|
params: []Type{&PrimFloat, &PrimFloat},
|
|
},
|
|
f: func(args []Expression) (Expression, error) {
|
|
var sum FloatValue = 0
|
|
for _, arg := range args {
|
|
if !isValue(arg) {
|
|
panic("not a value")
|
|
}
|
|
switch x := arg.(type) {
|
|
case *FloatValue:
|
|
sum += *x
|
|
default:
|
|
panic("type error")
|
|
}
|
|
}
|
|
return &sum, nil
|
|
},
|
|
},
|
|
"+": {
|
|
t: &FunctionType{
|
|
ret: &PrimInteger,
|
|
params: []Type{&PrimInteger, &PrimInteger},
|
|
},
|
|
f: func(args []Expression) (Expression, error) {
|
|
var sum IntValue = 0
|
|
for _, arg := range args {
|
|
if !isValue(arg) {
|
|
panic("not a value")
|
|
}
|
|
switch x := arg.(type) {
|
|
case *IntValue:
|
|
sum += *x
|
|
default:
|
|
panic("type error")
|
|
}
|
|
}
|
|
return &sum, nil
|
|
},
|
|
},
|
|
"-": {
|
|
t: &FunctionType{
|
|
ret: &PrimInteger,
|
|
params: []Type{&PrimInteger, &PrimInteger},
|
|
},
|
|
f: func(args []Expression) (Expression, error) {
|
|
var sum IntValue = 0
|
|
for _, arg := range args {
|
|
if !isValue(arg) {
|
|
panic("not a value")
|
|
}
|
|
switch x := arg.(type) {
|
|
case *IntValue:
|
|
sum += *x
|
|
default:
|
|
panic("type error")
|
|
}
|
|
}
|
|
return &sum, nil
|
|
},
|
|
},
|
|
}
|
|
for id, f := range functions {
|
|
expr.Substitute(id, &f)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
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 {
|
|
logger.Fatal(err)
|
|
}
|
|
p, err := consume(tk)
|
|
if err != nil {
|
|
logger.Fatal(err)
|
|
}
|
|
builtinFunctions(p)
|
|
_, err = p.TypeCheck(make(TypeEnvironment))
|
|
if err != nil {
|
|
logger.Fatal(err)
|
|
}
|
|
result, err := fullStep(p)
|
|
if err != nil {
|
|
logger.Fatal(err)
|
|
}
|
|
fmt.Println(reflect.TypeOf(result), result)
|
|
}
|