Introduce typed semantic analysis pipeline

This commit is contained in:
pavel 2026-08-27 19:28:24 +02:00
commit f4cd4f4458
30 changed files with 2079 additions and 2381 deletions

View file

@ -131,12 +131,6 @@ func (p *parser) parseProgram() (*Program, error) {
default:
return nil, fmt.Errorf("unsupported annotation %q", annotation.lexeme)
}
case p.check(tokenWorker):
decl, err := p.parseWorker()
if err != nil {
return nil, err
}
prog.Workers = append(prog.Workers, decl)
case p.check(tokenFun) || p.check(tokenSuspend):
fn, err := p.parseFunction()
if err != nil {
@ -338,68 +332,6 @@ func (p *parser) parseClass() (ClassDecl, error) {
return ClassDecl{Name: name.lexeme, Data: data, Fields: fields, Parents: parents, Methods: methods}, nil
}
func (p *parser) parseWorker() (WorkerDecl, error) {
if _, err := p.expect(tokenWorker, "expected 'worker'"); err != nil {
return WorkerDecl{}, err
}
name, err := p.expect(tokenIdent, "expected worker name")
if err != nil {
return WorkerDecl{}, err
}
if _, err := p.expect(tokenLBrace, "expected '{'"); err != nil {
return WorkerDecl{}, err
}
var fields []WorkerFieldDecl
var methods []FunctionDecl
for !p.check(tokenRBrace) && !p.check(tokenEOF) {
switch {
case p.match(tokenVal), p.match(tokenVar):
mutable := p.tokens[p.pos-1].kind == tokenVar
fieldName, err := p.expect(tokenIdent, "expected field name")
if err != nil {
return WorkerDecl{}, err
}
typ := ""
if p.match(tokenColon) {
parsed, err := p.parseTypeRef()
if err != nil {
return WorkerDecl{}, err
}
typ = parsed
}
if _, err := p.expect(tokenAssign, "expected '=' after field declaration"); err != nil {
return WorkerDecl{}, err
}
value, err := p.parseExpr(0)
if err != nil {
return WorkerDecl{}, err
}
fields = append(fields, WorkerFieldDecl{
Mutable: mutable,
Name: fieldName.lexeme,
Type: typ,
Value: value,
})
p.match(tokenSemicolon)
case p.check(tokenFun):
method, err := p.parseFunction()
if err != nil {
return WorkerDecl{}, err
}
methods = append(methods, method)
p.match(tokenSemicolon)
default:
tok := p.peek()
return WorkerDecl{}, fmt.Errorf("expected worker member at %d, found %q", tok.pos, tok.lexeme)
}
}
if _, err := p.expect(tokenRBrace, "expected '}'"); err != nil {
return WorkerDecl{}, err
}
return WorkerDecl{Name: name.lexeme, Fields: fields, Methods: methods}, nil
}
func (p *parser) parseClassParents() ([]string, error) {
if !p.match(tokenColon) {
return nil, nil
@ -626,6 +558,9 @@ func (p *parser) parseStmt() (Stmt, error) {
if p.check(tokenIdent) && p.peek().lexeme == "go" {
return nil, fmt.Errorf("bare go is removed; use launch inside a coroutine scope")
}
if p.check(tokenIdent) && p.peek().lexeme == "select" {
return nil, fmt.Errorf("select is removed; use structured coroutines and channel read()")
}
switch {
case p.match(tokenVal):
return p.parseVarDecl(false)
@ -646,25 +581,6 @@ func (p *parser) parseStmt() (Stmt, error) {
return nil, err
}
return ThrowStmt{Value: expr}, nil
case p.match(tokenGo):
var expr Expr
var err error
if p.check(tokenLBrace) {
body, err := p.parseBlock()
if err != nil {
return nil, err
}
expr = CallExpr{Callee: LambdaExpr{Body: body}}
} else {
expr, err = p.parseExpr(0)
if err != nil {
return nil, err
}
}
if _, ok := expr.(CallExpr); !ok {
return nil, fmt.Errorf("'go' expects a function call expression")
}
return GoStmt{Value: expr}, nil
case p.match(tokenDefer):
expr, err := p.parseExpr(0)
if err != nil {
@ -680,8 +596,6 @@ func (p *parser) parseStmt() (Stmt, error) {
return p.parseWhile()
case p.match(tokenFor):
return p.parseForEach()
case p.match(tokenSelect):
return p.parseSelect()
case p.match(tokenMatch):
return p.parseMatch()
case p.match(tokenTry):
@ -855,41 +769,6 @@ func (p *parser) parseMatchExpr() (Expr, error) {
return MatchExpr{Value: value, Cases: cases}, nil
}
func (p *parser) parseSelect() (Stmt, error) {
if _, err := p.expect(tokenLBrace, "expected '{' after select"); err != nil {
return nil, err
}
var cases []SelectCase
for !p.check(tokenRBrace) && !p.check(tokenEOF) {
source, err := p.parseExpr(0)
if err != nil {
return nil, err
}
if _, err := p.expect(tokenArrow, "expected '->' in select case"); err != nil {
return nil, err
}
var body []Stmt
if p.check(tokenLBrace) {
body, err = p.parseBlock()
if err != nil {
return nil, err
}
} else {
stmt, err := p.parseStmt()
if err != nil {
return nil, err
}
body = []Stmt{stmt}
p.match(tokenSemicolon)
}
cases = append(cases, SelectCase{Source: source, Body: body})
}
if _, err := p.expect(tokenRBrace, "expected '}' after select"); err != nil {
return nil, err
}
return SelectStmt{Cases: cases}, nil
}
func (p *parser) parseTryCatch() (Stmt, error) {
tryBody, err := p.parseBlock()
if err != nil {