about summary refs log tree commit diff
path: root/pkg/lang/parser/stmts.go
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-07-27 22:53:35 +0000
committerMel <einebeere@gmail.com>2022-07-27 22:53:35 +0000
commitd79973cb9df8660fe89810507557f5ba86256f30 (patch)
tree201774dae1fa63e6b962e7be9aeea20c033bb5e3 /pkg/lang/parser/stmts.go
parent4f23155ca7f8591cae0be6938610386513d24b7f (diff)
downloadjinx-d79973cb9df8660fe89810507557f5ba86256f30.tar.zst
jinx-d79973cb9df8660fe89810507557f5ba86256f30.zip
Parse type declaration statements
Diffstat (limited to 'pkg/lang/parser/stmts.go')
-rw-r--r--pkg/lang/parser/stmts.go126
1 files changed, 117 insertions, 9 deletions
diff --git a/pkg/lang/parser/stmts.go b/pkg/lang/parser/stmts.go
index 7d10e61..a0bba28 100644
--- a/pkg/lang/parser/stmts.go
+++ b/pkg/lang/parser/stmts.go
@@ -54,11 +54,15 @@ func (p *Parser) parseFnDeclStmt() (ast.Stmt, error) {
 		return ast.Stmt{}, err
 	}
 
-	params, err := p.parseFnParams()
+	hasThis, params, err := p.parseFnParams()
 	if err != nil {
 		return ast.Stmt{}, err
 	}
 
+	if hasThis {
+		return ast.Stmt{}, fmt.Errorf("function cannot have 'this' as a parameter")
+	}
+
 	block, err := p.parseBlock()
 	if err != nil {
 		return ast.Stmt{}, err
@@ -75,20 +79,36 @@ func (p *Parser) parseFnDeclStmt() (ast.Stmt, error) {
 	}, nil
 }
 
-func (p *Parser) parseFnParams() ([]ast.IdentNode, error) {
-	// FnParams = "(" ( IDENT ("," IDENT)* )? ")"
+func (p *Parser) parseFnParams() (bool, []ast.IdentNode, error) {
+	// FnParams = "(" ( (IDENT | "this") ("," IDENT)* )? ")"
 
 	if _, err := p.expect(token.LParen); err != nil {
-		return nil, err
+		return false, nil, err
 	}
 
+	hasThis := false
 	params := []ast.IdentNode{}
 
 	if p.peek().Kind != token.RParen {
 		for {
+			if p.peek().Kind == token.KwThis {
+				hasThis = true
+				if _, err := p.expect(token.KwThis); err != nil {
+					return false, nil, err
+				}
+
+				if p.peek().Kind != token.Comma {
+					break
+				} else {
+					if _, err := p.expect(token.Comma); err != nil {
+						return false, nil, err
+					}
+				}
+			}
+
 			param, err := p.parseIdent()
 			if err != nil {
-				return nil, err
+				return false, nil, err
 			}
 
 			params = append(params, param)
@@ -98,20 +118,108 @@ func (p *Parser) parseFnParams() ([]ast.IdentNode, error) {
 			}
 
 			if _, err := p.expect(token.Comma); err != nil {
-				return nil, err
+				return false, nil, err
 			}
 		}
 	}
 
 	if _, err := p.expect(token.RParen); err != nil {
-		return nil, err
+		return false, nil, err
 	}
 
-	return params, nil
+	return hasThis, params, nil
 }
 
 func (p *Parser) parseTypeDeclStmt() (ast.Stmt, error) {
-	panic("not implemented")
+	// TypeDeclStmt = "type" IDENT "{" (FnDeclStmt)* "}"
+
+	typeTok, err := p.expect(token.KwType)
+	if err != nil {
+		return ast.Stmt{}, err
+	}
+
+	name, err := p.parseIdent()
+	if err != nil {
+		return ast.Stmt{}, err
+	}
+
+	if _, err := p.expect(token.LBrace); err != nil {
+		return ast.Stmt{}, err
+	}
+
+	if err := p.parseStmtEnd(); err != nil {
+		return ast.Stmt{}, err
+	}
+
+	methods := make([]ast.TypeMethodNode, 0)
+
+	for p.peek().Kind != token.RBrace {
+		node, err := p.parseTypeMethodNode()
+		if err != nil {
+			return ast.Stmt{}, err
+		}
+
+		methods = append(methods, node)
+
+		if err := p.parseStmtEnd(); err != nil {
+			return ast.Stmt{}, err
+		}
+	}
+
+	if _, err := p.expect(token.RBrace); err != nil {
+		return ast.Stmt{}, err
+	}
+
+	return ast.Stmt{
+		At:   typeTok.At,
+		Kind: ast.StmtKindTypeDecl,
+		Value: ast.StmtTypeDecl{
+			Name:    name,
+			Methods: methods,
+		},
+	}, nil
+
+}
+
+func (p *Parser) parseTypeMethodNode() (ast.TypeMethodNode, error) {
+	var err error
+
+	startTok := p.peek()
+	isConstructor := false
+	name := ast.IdentNode{}
+
+	if p.peek().Kind == token.KwFn {
+		startTok, err = p.expect(token.KwFn)
+		if err != nil {
+			return ast.TypeMethodNode{}, err
+		}
+
+		name, err = p.parseIdent()
+		if err != nil {
+			return ast.TypeMethodNode{}, err
+		}
+	} else {
+		isConstructor = true
+	}
+
+	hasThis, params, err := p.parseFnParams()
+	if err != nil {
+		return ast.TypeMethodNode{}, err
+	}
+
+	block, err := p.parseBlock()
+	if err != nil {
+		return ast.TypeMethodNode{}, err
+	}
+
+	return ast.TypeMethodNode{
+		At:            startTok.At,
+		HasThis:       hasThis,
+		IsConstructor: isConstructor,
+		Name:          name,
+		Args:          params,
+		Body:          block,
+	}, nil
 }
 
 func (p *Parser) parseVarDeclStmt() (ast.Stmt, error) {