This commit is contained in:
silva guimaraes 2025-05-25 03:49:12 -03:00
parent e3bd2658cd
commit 7c40723537
3 changed files with 143 additions and 21 deletions

2
lex.go
View file

@ -49,6 +49,7 @@ var (
Newline = &Token{value: "\n"}
SingleQuote = &Token{value: "'"}
Let = &Token{value: "let"}
LambdaTok = &Token{value: "lambda"}
)
func (t Token) String() string {
@ -71,6 +72,7 @@ var knownTokens = []*Token{
Newline,
SingleQuote,
Let,
LambdaTok,
}
func (t *Token) Equals(a Lexeme) bool {

81
main.go
View file

@ -13,14 +13,35 @@ func (v *Value[T]) Step() (Expression, error) {
return v, nil
}
func (v *Value[T]) 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
}
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 (v *Identifier) Step() (Expression, error) {
switch v.value {
case "+":
@ -37,7 +58,6 @@ func (v *Identifier) Step() (Expression, error) {
sum += x.value.value
default:
return nil, fmt.Errorf("invalid type")
}
}
return &Value[int]{sum}, nil
@ -48,6 +68,50 @@ func (v *Identifier) Step() (Expression, error) {
}
}
func (v *Identifier) Replace(id Id, expr Expression) {
panic("!")
}
func (l *Lambda) Step() (Expression, error) {
f := func(args []Expression) (Expression, error) {
if len(args) != len(l.args) {
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)
}
}
}
if len(l.body) == 0 {
return &Value[int]{0}, nil
}
for i, expr := range l.body {
if isValue(expr) {
continue
}
r, err := expr.Step()
if err != nil {
return nil, err
}
l.body[i] = r
}
return l.body[len(l.body)-1], nil
}
return &Value[Function]{f}, nil
}
func (l *Lambda) Replace(id Id, expr Expression) {
panic("!")
}
func (v *List) Step() (Expression, error) {
for i, expr := range v.els {
if !isValue(expr) {
@ -73,6 +137,19 @@ func (v *List) Step() (Expression, error) {
return r, nil
}
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)
}
}
}
func isValue(e Expression) bool {
switch e.(type) {
case *Value[int], *Value[*Int], *Value[Function], *Quoted:
@ -86,7 +163,7 @@ func fullStep(e Expression) (Expression, error) {
for !isValue(e) {
n, err := e.Step()
if err != nil {
return n, nil
return nil, err
}
e = n
}

View file

@ -12,6 +12,7 @@ type Function func([]Expression) (Expression, error)
type Expression interface {
Step() (Expression, error)
Replace(Id, Expression)
// Visit(func(Expression) error)
}
@ -32,6 +33,11 @@ type Declaration struct {
expr Expression
}
type Lambda struct {
args []*Identifier
body []Expression
}
func (v Value[T]) String() string {
return fmt.Sprint(v.value)
}
@ -48,69 +54,65 @@ func (v List) String() string {
return fmt.Sprintf("(%s)", strings.Join(s, " "))
}
func (v *Lambda) String() string {
// var args = new(List)
// args.els = append(args.els, v.args...)
//
// var s []string
// for _, e := range v.args {
// s = append(s, fmt.Sprint(e))
// }
return "fuck you"
}
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)
@ -120,38 +122,79 @@ func parseList(in *Input) (Expression, error) {
}
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
}
func parseLambda(in *Input) (Expression, error) {
openingParens := in.Pop()
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 := decl.Pop()
if !tok.Equals(LambdaTok) {
return nil, noMatch
}
l, err := parseList(decl)
if err != nil {
return nil, err
}
list, ok := l.(*List)
if !ok {
return nil, noMatch
}
var args []*Identifier
for _, e := range list.els {
id, ok := e.(*Identifier)
if !ok {
return nil, noMatch
}
args = append(args, id)
}
var body []Expression
for decl.Len() > 0 {
n, err := consume(decl)
if err != nil {
return nil, err
}
body = append(body, n)
}
_ = in.Pop()
return &Lambda{args: args, body: body}, nil
}
type ParserFunc func(*Input) (Expression, error)
func consume(in *Input) (n Expression, err error) {
var parseFunctions = []ParserFunc{
parseQuotedObject,
parseLambda,
parseList,
parseSymbol,
parseValue,
parseLet,
}
for _, f := range parseFunctions {
start := in.Index()
n, err := f(in)
if err != nil {
in.Seek(start)
if errors.Is(err, noMatch) {
continue
} else {