This commit is contained in:
silva guimaraes 2025-08-23 20:02:18 -03:00
parent 0cd6040a1f
commit c1f75bb980
6 changed files with 140 additions and 67 deletions

View file

@ -235,6 +235,11 @@ type Symbol struct {
expr Expression expr Expression
} }
type Param struct {
id *Identifier
t Type
}
func (v *Symbol) Step() (Expression, error) { func (v *Symbol) Step() (Expression, error) {
if v.expr == nil { if v.expr == nil {
return nil, fmt.Errorf("unbound symbol %s at %s", v.id, v.id.position) return nil, fmt.Errorf("unbound symbol %s at %s", v.id, v.id.position)

View file

@ -42,12 +42,12 @@ func (in *Input) Seek(i int) {
in.index = i in.index = i
} }
func (in *Input) Take(amount int) *Input { func (in *Input) Take(offset int) *Input {
var out = &Input{ var out = &Input{
index: 0, index: 0,
input: in.input[in.index : in.index+amount], input: in.input[in.index : in.index+offset],
} }
in.index += amount in.index += offset
return out return out
} }
@ -70,3 +70,27 @@ func (in *Input) Find(open, close *Token) (int, bool) {
return 0, false return 0, false
} }
} }
func (in *Input) TakeParens(open, close *Token) (*Input, error) {
if in.input[in.index].Equals(open) {
return nil, noMatch
}
start := in.index
level := 1
idx := slices.IndexFunc(in.input[start+1:], func(a Lexeme) bool {
switch {
case a.Equals(open):
level++
case a.Equals(close):
level--
return level == 0
}
return false
})
if idx > -1 {
_ = in.Take(idx + 1)
return &Input{index: 0, input: in.input[start+1 : idx]}, nil
} else {
return nil, fmt.Errorf("unmatched parenthesis starting at %s", in.Peek(start).Position())
}
}

56
lex.go
View file

@ -22,40 +22,44 @@ func (p *position) Position() position {
return *p return *p
} }
type Range [2]position type (
Range [2]position
type token[T comparable] struct { token[T comparable] struct {
position position
value T value T
} }
type Lexeme interface { Lexeme interface {
Position() position Position() position
Equals(Lexeme) bool Equals(Lexeme) bool
} }
type Id string Id string
type Token token[string] Token token[string]
type IntToken token[int] IntToken token[int]
type FloatToken token[float64] FloatToken token[float64]
type Identifier token[Id] Identifier token[Id]
)
var ( var (
Lparen = &Token{value: "("} Lparen = &Token{value: "("}
Rparen = &Token{value: ")"} Rparen = &Token{value: ")"}
Space = &Token{value: " "} LsquareBracket = &Token{value: "["}
Tab = &Token{value: "\t"} RsquareBracket = &Token{value: "]"}
Newline = &Token{value: "\n"} Space = &Token{value: " "}
SingleQuote = &Token{value: "'"} Tab = &Token{value: "\t"}
Let = &Token{value: "let"} Newline = &Token{value: "\n"}
LambdaTok = &Token{value: "lambda"} SingleQuote = &Token{value: "'"}
If = &Token{value: "if"} Let = &Token{value: "let"}
TrueTok = &Token{value: "t"} LambdaTok = &Token{value: "lambda"}
NilTok = &Token{value: "nil"} If = &Token{value: "if"}
TrueTok = &Token{value: "t"}
NilTok = &Token{value: "nil"}
) )
func (t Token) String() string { func (t Token) String() string {
@ -107,7 +111,7 @@ func (t *Identifier) Equals(a Lexeme) bool {
var matchInt = regexp.MustCompile(`-?\d+`) var matchInt = regexp.MustCompile(`-?\d+`)
var matchFloat = regexp.MustCompile(`-?\d+\.\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 (

75
main.go
View file

@ -28,18 +28,27 @@ func fullStep(e Expression) (Expression, error) {
func builtinFunctions(expr Expression) { func builtinFunctions(expr Expression) {
functions := map[Id]BuiltInFunction{ functions := map[Id]BuiltInFunction{
// "quote": { "+.": {
// t: &FunctionType{ t: &FunctionType{
// ret: &PrimInteger, ret: &PrimFloat,
// params: , params: []Type{&PrimFloat, &PrimFloat},
// }, },
// f: func(e []Expression) (Expression, error) { f: func(args []Expression) (Expression, error) {
// if len(e) == 1 { var sum FloatValue = 0
// return &Quoted{e[0]}, nil for _, arg := range args {
// } if !isValue(arg) {
// return &Quoted{&List{e}}, nil panic("not a value")
// }, }
// }, switch x := arg.(type) {
case *FloatValue:
sum += *x
default:
panic("type error")
}
}
return &sum, nil
},
},
"+": { "+": {
t: &FunctionType{ t: &FunctionType{
ret: &PrimInteger, ret: &PrimInteger,
@ -61,27 +70,27 @@ func builtinFunctions(expr Expression) {
return &sum, nil return &sum, nil
}, },
}, },
// "-": func(args []Expression) (Expression, error) { "-": {
// v0, ok := args[0].(*IntValue) t: &FunctionType{
// if !ok { ret: &PrimInteger,
// return nil, fmt.Errorf("integer value was expected") params: []Type{&PrimInteger, &PrimInteger},
// } },
// v1, ok := args[1].(*IntValue) f: func(args []Expression) (Expression, error) {
// if !ok { var sum IntValue = 0
// return nil, fmt.Errorf("integer value was expected") for _, arg := range args {
// } if !isValue(arg) {
// var result IntValue = (*v0 - *v1) panic("not a value")
// return &result, nil }
// }, switch x := arg.(type) {
// "=": func(args []Expression) (Expression, error) { case *IntValue:
// if reflect.TypeOf(args[0]) != reflect.TypeOf(args[1]) { sum += *x
// return nil, fmt.Errorf("unmatched types") default:
// } panic("type error")
// v0 := reflect.ValueOf(args[0]) }
// v1 := reflect.ValueOf(args[1]) }
// var result BoolValue = BoolValue(v0.Equal(v1)) return &sum, nil
// return &result, nil },
// }, },
} }
for id, f := range functions { for id, f := range functions {
expr.Substitute(id, &f) expr.Substitute(id, &f)

View file

@ -96,6 +96,35 @@ func parseValue(in *Input) (Expression, error) {
} }
} }
func parseParamList(in *Input) (Expression, error) {
list, err := in.TakeParens(Lparen, Rparen)
if err != nil {
return nil, err
}
var params []*Symbol
for list.Len() > 0 {
p, err := list.TakeParens(LsquareBracket, RsquareBracket)
if err != nil {
return nil, err
}
if p.Len() != 2 {
return nil, fmt.Errorf("expected parameter in the following form: [identifier type]")
}
id, ok := p.Peek(0).(*Identifier)
if !ok {
return nil, noMatch
}
typ, ok := p.Peek(1).(*Identifier)
if !ok {
return nil, noMatch
}
params = append(params, &Symbol{
id: ,
})
}
return args, nil
}
func parseList(in *Input) (Expression, error) { func parseList(in *Input) (Expression, error) {
openingParens, ok := in.Pop() openingParens, ok := in.Pop()
if !ok { if !ok {
@ -192,11 +221,7 @@ 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, ok := decl.Pop() if tok, ok := decl.Pop(); !ok || !tok.Equals(LambdaTok) {
if !ok {
return nil, noMatch
}
if !tok.Equals(LambdaTok) {
return nil, noMatch return nil, noMatch
} }
l, err := parseList(decl) l, err := parseList(decl)

View file

@ -84,6 +84,12 @@ func (fa *FunctionType) Equal(b Type) bool {
return fa.ret.Equal(fb.ret) return fa.ret.Equal(fb.ret)
} }
// func FromId(id Id) (Type, error) {
// switch id {
// case "integer":
// }
// }
// func (fa *VariadicListType) Equal(b Type) bool { // func (fa *VariadicListType) Equal(b Type) bool {
// return false // return false
// } // }