This commit is contained in:
silva guimaraes 2025-05-25 21:56:22 -03:00
parent 7c40723537
commit 8f5b16878f
4 changed files with 316 additions and 144 deletions

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
}