Commit inicial

This commit is contained in:
silva guimaraes 2025-05-25 02:35:11 -03:00
commit e3bd2658cd
5 changed files with 512 additions and 0 deletions

164
parse.go Normal file
View file

@ -0,0 +1,164 @@
package main
import (
"errors"
"fmt"
"strings"
)
var noMatch = errors.New("no match")
type Function func([]Expression) (Expression, error)
type Expression interface {
Step() (Expression, error)
// Visit(func(Expression) error)
}
type List struct {
els []Expression
}
type Value[T interface{ *Int | int | Function }] struct {
value T
}
type Quoted struct {
expr Expression
}
type Declaration struct {
id *Identifier
expr Expression
}
func (v Value[T]) String() string {
return fmt.Sprint(v.value)
}
func (v Quoted) String() string {
return fmt.Sprintf("'%s", v.expr)
}
func (v List) String() string {
var s []string
for _, e := range v.els {
s = append(s, fmt.Sprint(e))
}
return fmt.Sprintf("(%s)", strings.Join(s, " "))
}
func parseQuotedObject(in *Input) (Expression, error) {
start := in.Index()
l := in.Pop()
switch {
case l.Equals(SingleQuote):
n, err := consume(in)
if err != nil {
in.Seek(start)
return nil, err
}
return &Quoted{n}, nil
default:
in.Seek(start)
return nil, noMatch
}
}
func parseSymbol(in *Input) (Expression, error) {
start := in.Index()
l := in.Pop()
switch x := l.(type) {
case *Identifier:
return x, nil
default:
in.Seek(start)
return nil, noMatch
}
}
func parseValue(in *Input) (Expression, error) {
start := in.Index()
l := in.Pop()
switch x := l.(type) {
case *Int:
return &Value[*Int]{x}, nil
default:
in.Seek(start)
return nil, noMatch
}
}
func parseList(in *Input) (Expression, error) {
start := in.Index()
openingParens := in.Pop()
if !openingParens.Equals(Lparen) {
in.Seek(start)
return nil, noMatch
}
idx, ok := in.Find(Lparen, Rparen)
if !ok {
in.Seek(start)
return nil, fmt.Errorf("unmatched parenthesis starting at %s", openingParens.Position())
}
if idx == 0 {
in.Seek(start)
return nil, fmt.Errorf("no function declared at %s", openingParens.Position())
}
list := in.Take(idx)
var args = new(List)
for list.Len() > 0 {
arg, err := consume(list)
if err != nil {
in.Seek(start)
return nil, err
}
args.els = append(args.els, arg)
}
_ = in.Pop()
return args, nil
}
func parseLet(in *Input) (Expression, error) {
start := in.Index()
token := in.Pop()
if !token.Equals(Let) {
in.Seek(start)
return nil, noMatch
}
id, ok := in.Pop().(*Identifier)
if !ok {
in.Seek(start)
return nil, noMatch
}
expr, err := consume(in)
if err != nil {
in.Seek(start)
return nil, noMatch
}
return &Declaration{id: id, expr: expr}, nil
}
type ParserFunc func(*Input) (Expression, error)
func consume(in *Input) (n Expression, err error) {
var parseFunctions = []ParserFunc{
parseQuotedObject,
parseList,
parseSymbol,
parseValue,
parseLet,
}
for _, f := range parseFunctions {
n, err := f(in)
if err != nil {
if errors.Is(err, noMatch) {
continue
} else {
return nil, err
}
}
return n, nil
}
return nil, fmt.Errorf("unrecognized construction: %s", in)
}