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
}
type Param struct {
id *Identifier
t Type
}
func (v *Symbol) Step() (Expression, error) {
if v.expr == nil {
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
}
func (in *Input) Take(amount int) *Input {
func (in *Input) Take(offset int) *Input {
var out = &Input{
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
}
@ -70,3 +70,27 @@ func (in *Input) Find(open, close *Token) (int, bool) {
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
}
type Range [2]position
type (
Range [2]position
type token[T comparable] struct {
position
value T
}
token[T comparable] struct {
position
value T
}
type Lexeme interface {
Position() position
Equals(Lexeme) bool
}
Lexeme interface {
Position() position
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 (
Lparen = &Token{value: "("}
Rparen = &Token{value: ")"}
Space = &Token{value: " "}
Tab = &Token{value: "\t"}
Newline = &Token{value: "\n"}
SingleQuote = &Token{value: "'"}
Let = &Token{value: "let"}
LambdaTok = &Token{value: "lambda"}
If = &Token{value: "if"}
TrueTok = &Token{value: "t"}
NilTok = &Token{value: "nil"}
Lparen = &Token{value: "("}
Rparen = &Token{value: ")"}
LsquareBracket = &Token{value: "["}
RsquareBracket = &Token{value: "]"}
Space = &Token{value: " "}
Tab = &Token{value: "\t"}
Newline = &Token{value: "\n"}
SingleQuote = &Token{value: "'"}
Let = &Token{value: "let"}
LambdaTok = &Token{value: "lambda"}
If = &Token{value: "if"}
TrueTok = &Token{value: "t"}
NilTok = &Token{value: "nil"}
)
func (t Token) String() string {
@ -107,7 +111,7 @@ func (t *Identifier) Equals(a Lexeme) bool {
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) {
var (

75
main.go
View file

@ -28,18 +28,27 @@ func fullStep(e Expression) (Expression, error) {
func builtinFunctions(expr Expression) {
functions := map[Id]BuiltInFunction{
// "quote": {
// t: &FunctionType{
// ret: &PrimInteger,
// params: ,
// },
// f: func(e []Expression) (Expression, error) {
// if len(e) == 1 {
// return &Quoted{e[0]}, nil
// }
// return &Quoted{&List{e}}, nil
// },
// },
"+.": {
t: &FunctionType{
ret: &PrimFloat,
params: []Type{&PrimFloat, &PrimFloat},
},
f: func(args []Expression) (Expression, error) {
var sum FloatValue = 0
for _, arg := range args {
if !isValue(arg) {
panic("not a value")
}
switch x := arg.(type) {
case *FloatValue:
sum += *x
default:
panic("type error")
}
}
return &sum, nil
},
},
"+": {
t: &FunctionType{
ret: &PrimInteger,
@ -61,27 +70,27 @@ func builtinFunctions(expr Expression) {
return &sum, nil
},
},
// "-": func(args []Expression) (Expression, error) {
// v0, ok := args[0].(*IntValue)
// if !ok {
// return nil, fmt.Errorf("integer value was expected")
// }
// v1, ok := args[1].(*IntValue)
// if !ok {
// return nil, fmt.Errorf("integer value was expected")
// }
// var result IntValue = (*v0 - *v1)
// return &result, nil
// },
// "=": func(args []Expression) (Expression, error) {
// if reflect.TypeOf(args[0]) != reflect.TypeOf(args[1]) {
// return nil, fmt.Errorf("unmatched types")
// }
// v0 := reflect.ValueOf(args[0])
// v1 := reflect.ValueOf(args[1])
// var result BoolValue = BoolValue(v0.Equal(v1))
// return &result, nil
// },
"-": {
t: &FunctionType{
ret: &PrimInteger,
params: []Type{&PrimInteger, &PrimInteger},
},
f: func(args []Expression) (Expression, error) {
var sum IntValue = 0
for _, arg := range args {
if !isValue(arg) {
panic("not a value")
}
switch x := arg.(type) {
case *IntValue:
sum += *x
default:
panic("type error")
}
}
return &sum, nil
},
},
}
for id, f := range functions {
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) {
openingParens, ok := in.Pop()
if !ok {
@ -192,11 +221,7 @@ func parseLambda(in *Input) (Expression, error) {
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, ok := decl.Pop(); !ok || !tok.Equals(LambdaTok) {
return nil, noMatch
}
l, err := parseList(decl)

View file

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