• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

forst-lang / forst / 15377875600

01 Jun 2025 05:59PM UTC coverage: 28.203% (+1.0%) from 27.2%
15377875600

Pull #13

github

haveyaseen
Add more tests and fix parser issues
Pull Request #13: feat: Add control flow, references, and map literals

201 of 535 new or added lines in 21 files covered. (37.57%)

3 existing lines in 3 files now uncovered.

1378 of 4886 relevant lines covered (28.2%)

3.22 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.8
/forst/internal/parser/function.go
1
package parser
2

3
import (
4
        "forst/internal/ast"
5
)
6

7
func (p *Parser) parseParameterType() ast.TypeNode {
4✔
8
        next := p.peek()
4✔
9
        // TODO: Even if the next token is a dot this could be a type without any constraints
4✔
10
        if next.Type == ast.TokenDot || next.Type == ast.TokenLParen {
4✔
11
                assertion := p.parseAssertionChain(true)
×
12
                return ast.TypeNode{
×
13
                        Ident:     ast.TypeAssertion,
×
14
                        Assertion: &assertion,
×
15
                }
×
16
        }
×
17
        return p.parseType(TypeIdentOpts{AllowLowercaseTypes: false})
4✔
18
}
19

20
func (p *Parser) parseDestructuredParameter() ast.ParamNode {
×
21
        p.expect(ast.TokenLBrace)
×
22
        fields := []string{}
×
23

×
24
        // Parse fields until we hit closing brace
×
25
        for p.current().Type != ast.TokenRBrace {
×
26
                name := p.expect(ast.TokenIdentifier)
×
27
                fields = append(fields, name.Value)
×
28

×
29
                // Handle comma between fields
×
30
                if p.current().Type == ast.TokenComma {
×
31
                        p.advance()
×
32
                }
×
33
        }
34

35
        p.expect(ast.TokenRBrace)
×
36
        p.expect(ast.TokenColon)
×
37

×
38
        paramType := p.parseParameterType()
×
39

×
40
        return ast.DestructuredParamNode{
×
41
                Fields: fields,
×
42
                Type:   paramType,
×
43
        }
×
44
}
45

46
func (p *Parser) parseSimpleParameter() ast.ParamNode {
4✔
47
        ident := p.expect(ast.TokenIdentifier)
4✔
48
        // If the next token is a colon, consume it; otherwise, assume the next token is the type
4✔
49
        if p.current().Type == ast.TokenColon {
8✔
50
                p.advance()
4✔
51
        }
4✔
52
        typ := p.parseParameterType()
4✔
53
        return ast.SimpleParamNode{
4✔
54
                Ident: ast.Ident{ID: ast.Identifier(ident.Value)},
4✔
55
                Type:  typ,
4✔
56
        }
4✔
57
}
58

59
func (p *Parser) parseParameter() ast.ParamNode {
4✔
60
        switch p.current().Type {
4✔
61
        case ast.TokenIdentifier:
4✔
62
                return p.parseSimpleParameter()
4✔
63
        case ast.TokenLBrace:
×
64
                return p.parseDestructuredParameter()
×
65
        default:
×
66
                panic(parseErrorMessage(p.current(), "Expected parameter"))
×
67
        }
68
}
69

70
// Parse function parameters
71
func (p *Parser) parseFunctionSignature() []ast.ParamNode {
8✔
72
        p.expect(ast.TokenLParen)
8✔
73
        params := []ast.ParamNode{}
8✔
74

8✔
75
        // Handle empty parameter list
8✔
76
        if p.current().Type == ast.TokenRParen {
13✔
77
                p.advance()
5✔
78
                return params
5✔
79
        }
5✔
80

81
        // Parse parameters
82
        for {
6✔
83
                param := p.parseParameter()
3✔
84
                switch param.(type) {
3✔
85
                case ast.DestructuredParamNode:
×
86
                        logParsedNodeWithMessage(param, "Parsed destructured function param")
×
87
                default:
3✔
88
                        logParsedNodeWithMessage(param, "Parsed function param")
3✔
89
                }
90
                params = append(params, param)
3✔
91

3✔
92
                // Check if there are more parameters
3✔
93
                if p.current().Type == ast.TokenComma {
3✔
94
                        p.advance()
×
95
                } else {
3✔
96
                        break
3✔
97
                }
98
        }
99

100
        p.expect(ast.TokenRParen)
3✔
101
        return params
3✔
102
}
103

104
func (p *Parser) parseReturnType() []ast.TypeNode {
8✔
105
        returnType := []ast.TypeNode{}
8✔
106
        if p.current().Type == ast.TokenColon {
8✔
107
                p.advance() // Consume the colon
×
NEW
108
                returnType = append(returnType, p.parseType(TypeIdentOpts{AllowLowercaseTypes: false}))
×
109
        }
×
110
        return returnType
8✔
111
}
112

113
func (p *Parser) parseReturnStatement() ast.ReturnNode {
7✔
114
        p.advance() // Move past `return`
7✔
115

7✔
116
        returnExpression := p.parseExpression()
7✔
117

7✔
118
        return ast.ReturnNode{
7✔
119
                Value: returnExpression,
7✔
120
                Type:  ast.TypeNode{Ident: ast.TypeImplicit},
7✔
121
        }
7✔
122
}
7✔
123

124
func (p *Parser) parseFunctionBody() []ast.Node {
8✔
125
        return p.parseBlock(&BlockContext{AllowReturn: true})
8✔
126
}
8✔
127

128
// Parse a function definition
129
func (p *Parser) parseFunctionDefinition() ast.FunctionNode {
8✔
130
        p.expect(ast.TokenFunction)           // Expect `fn`
8✔
131
        name := p.expect(ast.TokenIdentifier) // Function name
8✔
132

8✔
133
        p.context.Scope.functionName = name.Value
8✔
134

8✔
135
        params := p.parseFunctionSignature() // Parse function parameters
8✔
136

8✔
137
        returnType := p.parseReturnType()
8✔
138

8✔
139
        body := p.parseFunctionBody()
8✔
140

8✔
141
        node := ast.FunctionNode{
8✔
142
                Ident:       ast.Ident{ID: ast.Identifier(name.Value)},
8✔
143
                ReturnTypes: returnType,
8✔
144
                Params:      params,
8✔
145
                Body:        body,
8✔
146
        }
8✔
147

8✔
148
        return node
8✔
149
}
8✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc