Introduce typed semantic analysis pipeline
This commit is contained in:
parent
117d188194
commit
f4cd4f4458
30 changed files with 2079 additions and 2381 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue