Move LSP semantics into typed analysis

This commit is contained in:
pavel 2026-08-27 21:28:11 +02:00
commit bac1183593
26 changed files with 1232 additions and 637 deletions

View file

@ -17,7 +17,14 @@ func Parse(input string) (*Program, error) {
return nil, err
}
p := &parser{tokens: tokens}
return p.parseProgram()
program, err := p.parseProgram()
if err != nil {
return nil, err
}
if err := hydrateTypeRefs(program); err != nil {
return nil, err
}
return program, nil
}
func (p *parser) parseProgram() (*Program, error) {
@ -292,6 +299,10 @@ func (p *parser) parseClass() (ClassDecl, error) {
if err != nil {
return ClassDecl{}, err
}
typeParams, err := p.parseTypeParameters()
if err != nil {
return ClassDecl{}, err
}
var fields []FieldDecl
if p.match(tokenLParen) {
fields, err = p.parseClassFields()
@ -308,7 +319,7 @@ func (p *parser) parseClass() (ClassDecl, error) {
return ClassDecl{}, err
}
if !p.match(tokenLBrace) {
return ClassDecl{Name: name.lexeme, Data: data, Fields: fields, Parents: parents, Methods: nil}, nil
return ClassDecl{Name: name.lexeme, TypeParams: typeParams, Data: data, Fields: fields, Parents: parents, Methods: nil}, nil
}
var methods []FunctionDecl
@ -329,7 +340,7 @@ func (p *parser) parseClass() (ClassDecl, error) {
return ClassDecl{}, err
}
return ClassDecl{Name: name.lexeme, Data: data, Fields: fields, Parents: parents, Methods: methods}, nil
return ClassDecl{Name: name.lexeme, TypeParams: typeParams, Data: data, Fields: fields, Parents: parents, Methods: methods}, nil
}
func (p *parser) parseClassParents() ([]string, error) {
@ -467,6 +478,7 @@ func (p *parser) parseFunction() (FunctionDecl, error) {
return FunctionDecl{
Name: signature.Name,
TypeParams: signature.TypeParams,
Params: signature.Params,
ReturnType: signature.ReturnType,
Body: body,
@ -483,6 +495,10 @@ func (p *parser) parseFunctionSignature() (FunctionSignature, error) {
if err != nil {
return FunctionSignature{}, err
}
typeParams, err := p.parseTypeParameters()
if err != nil {
return FunctionSignature{}, err
}
if _, err := p.expect(tokenLParen, "expected '('"); err != nil {
return FunctionSignature{}, err
}
@ -505,12 +521,39 @@ func (p *parser) parseFunctionSignature() (FunctionSignature, error) {
return FunctionSignature{
Name: name.lexeme,
TypeParams: typeParams,
Params: params,
ReturnType: returnType,
Suspend: suspend,
}, nil
}
func (p *parser) parseTypeParameters() ([]string, error) {
if !p.match(tokenLt) {
return nil, nil
}
var params []string
seen := map[string]bool{}
for {
name, err := p.expect(tokenIdent, "expected type parameter")
if err != nil {
return nil, err
}
if seen[name.lexeme] {
return nil, fmt.Errorf("duplicate type parameter %s", name.lexeme)
}
seen[name.lexeme] = true
params = append(params, name.lexeme)
if !p.match(tokenComma) {
break
}
}
if _, err := p.expect(tokenGt, "expected '>' after type parameters"); err != nil {
return nil, err
}
return params, nil
}
func (p *parser) parseParams() ([]Param, error) {
var params []Param
if p.check(tokenRParen) {
@ -528,7 +571,11 @@ func (p *parser) parseParams() ([]Param, error) {
if err != nil {
return nil, err
}
params = append(params, Param{Name: name.lexeme, Type: typ})
ref, err := ParseTypeRef(typ)
if err != nil {
return nil, err
}
params = append(params, Param{Name: name.lexeme, Type: typ, TypeRef: ref})
if !p.match(tokenComma) {
return params, nil
}
@ -832,7 +879,7 @@ func (p *parser) parseVarDecl(mutable bool) (Stmt, error) {
return nil, err
}
if len(names) == 1 {
return VarDecl{Mutable: mutable, Name: name, Type: typ, Value: value}, nil
return VarDecl{Mutable: mutable, Name: name, Pos: names[0].pos, Type: typ, Value: value}, nil
}
decl := MultiVarDecl{Mutable: mutable, Names: make([]string, 0, len(names)), Value: value}
for _, name := range names {
@ -908,7 +955,7 @@ func (p *parser) parsePrefix() (Expr, error) {
tok := p.advance()
switch tok.kind {
case tokenIdent:
return p.parsePostfix(IdentExpr{Name: tok.lexeme})
return p.parsePostfix(IdentExpr{Name: tok.lexeme, Pos: tok.pos})
case tokenInt:
return IntExpr{Value: tok.lexeme}, nil
case tokenFloat:
@ -999,6 +1046,10 @@ func (p *parser) parseLambdaParams() ([]Param, bool, error) {
return nil, false, err
}
param.Type = typ
param.TypeRef, err = ParseTypeRef(typ)
if err != nil {
return nil, false, err
}
}
params = append(params, param)
if !p.match(tokenComma) {
@ -1028,13 +1079,13 @@ func (p *parser) parsePostfix(expr Expr) (Expr, error) {
if !selectorName(name.lexeme) {
return nil, fmt.Errorf("expected selector name at %d, found %q", name.pos, name.lexeme)
}
expr = SelectorExpr{Receiver: expr, Name: name.lexeme}
expr = SelectorExpr{Receiver: expr, Name: name.lexeme, NamePos: name.pos}
case p.match(tokenSafeDot):
name := p.advance()
if !selectorName(name.lexeme) {
return nil, fmt.Errorf("expected selector name at %d, found %q", name.pos, name.lexeme)
}
expr = SafeSelectorExpr{Receiver: expr, Name: name.lexeme}
expr = SafeSelectorExpr{Receiver: expr, Name: name.lexeme, NamePos: name.pos}
case p.match(tokenDoubleBang):
expr = NonNullExpr{Value: expr}
case p.match(tokenQuestion):