Lambda
This commit is contained in:
parent
e3bd2658cd
commit
7c40723537
3 changed files with 143 additions and 21 deletions
2
lex.go
2
lex.go
|
|
@ -49,6 +49,7 @@ var (
|
||||||
Newline = &Token{value: "\n"}
|
Newline = &Token{value: "\n"}
|
||||||
SingleQuote = &Token{value: "'"}
|
SingleQuote = &Token{value: "'"}
|
||||||
Let = &Token{value: "let"}
|
Let = &Token{value: "let"}
|
||||||
|
LambdaTok = &Token{value: "lambda"}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t Token) String() string {
|
func (t Token) String() string {
|
||||||
|
|
@ -71,6 +72,7 @@ var knownTokens = []*Token{
|
||||||
Newline,
|
Newline,
|
||||||
SingleQuote,
|
SingleQuote,
|
||||||
Let,
|
Let,
|
||||||
|
LambdaTok,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Token) Equals(a Lexeme) bool {
|
func (t *Token) Equals(a Lexeme) bool {
|
||||||
|
|
|
||||||
81
main.go
81
main.go
|
|
@ -13,14 +13,35 @@ func (v *Value[T]) Step() (Expression, error) {
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Value[T]) Replace(Id, Expression) {
|
||||||
|
}
|
||||||
|
|
||||||
func (v *Quoted) Step() (Expression, error) {
|
func (v *Quoted) Step() (Expression, error) {
|
||||||
return v, nil
|
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
|
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) {
|
func (v *Identifier) Step() (Expression, error) {
|
||||||
switch v.value {
|
switch v.value {
|
||||||
case "+":
|
case "+":
|
||||||
|
|
@ -37,7 +58,6 @@ func (v *Identifier) Step() (Expression, error) {
|
||||||
sum += x.value.value
|
sum += x.value.value
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid type")
|
return nil, fmt.Errorf("invalid type")
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &Value[int]{sum}, nil
|
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) {
|
func (v *List) Step() (Expression, error) {
|
||||||
for i, expr := range v.els {
|
for i, expr := range v.els {
|
||||||
if !isValue(expr) {
|
if !isValue(expr) {
|
||||||
|
|
@ -73,6 +137,19 @@ func (v *List) Step() (Expression, error) {
|
||||||
return r, nil
|
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 {
|
func isValue(e Expression) bool {
|
||||||
switch e.(type) {
|
switch e.(type) {
|
||||||
case *Value[int], *Value[*Int], *Value[Function], *Quoted:
|
case *Value[int], *Value[*Int], *Value[Function], *Quoted:
|
||||||
|
|
@ -86,7 +163,7 @@ func fullStep(e Expression) (Expression, error) {
|
||||||
for !isValue(e) {
|
for !isValue(e) {
|
||||||
n, err := e.Step()
|
n, err := e.Step()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, nil
|
return nil, err
|
||||||
}
|
}
|
||||||
e = n
|
e = n
|
||||||
}
|
}
|
||||||
|
|
|
||||||
81
parse.go
81
parse.go
|
|
@ -12,6 +12,7 @@ type Function func([]Expression) (Expression, error)
|
||||||
|
|
||||||
type Expression interface {
|
type Expression interface {
|
||||||
Step() (Expression, error)
|
Step() (Expression, error)
|
||||||
|
Replace(Id, Expression)
|
||||||
// Visit(func(Expression) error)
|
// Visit(func(Expression) error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,6 +33,11 @@ type Declaration struct {
|
||||||
expr Expression
|
expr Expression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Lambda struct {
|
||||||
|
args []*Identifier
|
||||||
|
body []Expression
|
||||||
|
}
|
||||||
|
|
||||||
func (v Value[T]) String() string {
|
func (v Value[T]) String() string {
|
||||||
return fmt.Sprint(v.value)
|
return fmt.Sprint(v.value)
|
||||||
}
|
}
|
||||||
|
|
@ -48,69 +54,65 @@ func (v List) String() string {
|
||||||
return fmt.Sprintf("(%s)", strings.Join(s, " "))
|
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) {
|
func parseQuotedObject(in *Input) (Expression, error) {
|
||||||
start := in.Index()
|
|
||||||
l := in.Pop()
|
l := in.Pop()
|
||||||
switch {
|
switch {
|
||||||
case l.Equals(SingleQuote):
|
case l.Equals(SingleQuote):
|
||||||
n, err := consume(in)
|
n, err := consume(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
in.Seek(start)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Quoted{n}, nil
|
return &Quoted{n}, nil
|
||||||
default:
|
default:
|
||||||
in.Seek(start)
|
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSymbol(in *Input) (Expression, error) {
|
func parseSymbol(in *Input) (Expression, error) {
|
||||||
start := in.Index()
|
|
||||||
l := in.Pop()
|
l := in.Pop()
|
||||||
switch x := l.(type) {
|
switch x := l.(type) {
|
||||||
case *Identifier:
|
case *Identifier:
|
||||||
return x, nil
|
return x, nil
|
||||||
default:
|
default:
|
||||||
in.Seek(start)
|
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseValue(in *Input) (Expression, error) {
|
func parseValue(in *Input) (Expression, error) {
|
||||||
start := in.Index()
|
|
||||||
l := in.Pop()
|
l := in.Pop()
|
||||||
switch x := l.(type) {
|
switch x := l.(type) {
|
||||||
case *Int:
|
case *Int:
|
||||||
return &Value[*Int]{x}, nil
|
return &Value[*Int]{x}, nil
|
||||||
default:
|
default:
|
||||||
in.Seek(start)
|
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseList(in *Input) (Expression, error) {
|
func parseList(in *Input) (Expression, error) {
|
||||||
start := in.Index()
|
|
||||||
openingParens := in.Pop()
|
openingParens := in.Pop()
|
||||||
if !openingParens.Equals(Lparen) {
|
if !openingParens.Equals(Lparen) {
|
||||||
in.Seek(start)
|
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
idx, ok := in.Find(Lparen, Rparen)
|
idx, ok := in.Find(Lparen, Rparen)
|
||||||
if !ok {
|
if !ok {
|
||||||
in.Seek(start)
|
|
||||||
return nil, fmt.Errorf("unmatched parenthesis starting at %s", openingParens.Position())
|
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)
|
list := in.Take(idx)
|
||||||
var args = new(List)
|
var args = new(List)
|
||||||
for list.Len() > 0 {
|
for list.Len() > 0 {
|
||||||
arg, err := consume(list)
|
arg, err := consume(list)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
in.Seek(start)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
args.els = append(args.els, arg)
|
args.els = append(args.els, arg)
|
||||||
|
|
@ -120,38 +122,79 @@ func parseList(in *Input) (Expression, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseLet(in *Input) (Expression, error) {
|
func parseLet(in *Input) (Expression, error) {
|
||||||
start := in.Index()
|
|
||||||
token := in.Pop()
|
token := in.Pop()
|
||||||
if !token.Equals(Let) {
|
if !token.Equals(Let) {
|
||||||
in.Seek(start)
|
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
id, ok := in.Pop().(*Identifier)
|
id, ok := in.Pop().(*Identifier)
|
||||||
if !ok {
|
if !ok {
|
||||||
in.Seek(start)
|
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
expr, err := consume(in)
|
expr, err := consume(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
in.Seek(start)
|
|
||||||
return nil, noMatch
|
return nil, noMatch
|
||||||
}
|
}
|
||||||
return &Declaration{id: id, expr: expr}, nil
|
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)
|
type ParserFunc func(*Input) (Expression, error)
|
||||||
|
|
||||||
func consume(in *Input) (n Expression, err error) {
|
func consume(in *Input) (n Expression, err error) {
|
||||||
var parseFunctions = []ParserFunc{
|
var parseFunctions = []ParserFunc{
|
||||||
parseQuotedObject,
|
parseQuotedObject,
|
||||||
|
parseLambda,
|
||||||
parseList,
|
parseList,
|
||||||
parseSymbol,
|
parseSymbol,
|
||||||
parseValue,
|
parseValue,
|
||||||
parseLet,
|
parseLet,
|
||||||
}
|
}
|
||||||
for _, f := range parseFunctions {
|
for _, f := range parseFunctions {
|
||||||
|
start := in.Index()
|
||||||
n, err := f(in)
|
n, err := f(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
in.Seek(start)
|
||||||
if errors.Is(err, noMatch) {
|
if errors.Is(err, noMatch) {
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue