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

forst-lang / forst / 15356815762

30 May 2025 10:21PM UTC coverage: 24.245% (+9.3%) from 14.947%
15356815762

push

github

web-flow
feat: Add type guards and improve type handling (#9)

257 of 1104 new or added lines in 37 files covered. (23.28%)

19 existing lines in 13 files now uncovered.

1035 of 4269 relevant lines covered (24.24%)

2.71 hits per line

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

68.75
/forst/internal/typechecker/scope_stack.go
1
package typechecker
2

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

7
// Manages a stack of scopes during type checking
8
type ScopeStack struct {
9
        scopes  map[NodeHash]*Scope
10
        current *Scope
11
        Hasher  *StructuralHasher
12
}
13

14
// Creates a new stack with a global scope
15
func NewScopeStack(hasher *StructuralHasher) *ScopeStack {
5✔
16
        globalScope := &Scope{
5✔
17
                Symbols: make(map[ast.Identifier]Symbol),
5✔
18
        }
5✔
19
        return &ScopeStack{
5✔
20
                scopes:  make(map[NodeHash]*Scope),
5✔
21
                current: globalScope,
5✔
22
                Hasher:  hasher,
5✔
23
        }
5✔
24
}
5✔
25

26
// Creates and pushes a new scope for the given AST node
27
func (ss *ScopeStack) PushScope(node ast.Node) {
5✔
28
        hash := ss.Hasher.HashNode(node)
5✔
29
        scope := &Scope{
5✔
30
                Parent:   ss.current,
5✔
31
                Node:     node,
5✔
32
                Symbols:  make(map[ast.Identifier]Symbol),
5✔
33
                Children: make([]*Scope, 0),
5✔
34
        }
5✔
35
        ss.current.Children = append(ss.current.Children, scope)
5✔
36
        ss.current = scope
5✔
37
        ss.scopes[hash] = scope
5✔
38
}
5✔
39

40
// Returns to the parent scope if one exists
41
func (ss *ScopeStack) PopScope() {
5✔
42
        if ss.current.Parent != nil {
10✔
43
                ss.current = ss.current.Parent
5✔
44
        }
5✔
45
}
46

47
func (ss *ScopeStack) CurrentScope() *Scope {
18✔
48
        return ss.current
18✔
49
}
18✔
50

51
// Looks up a scope by its AST node
52
func (ss *ScopeStack) FindScope(node ast.Node) *Scope {
×
53
        hash := ss.Hasher.HashNode(node)
×
54
        return ss.scopes[hash]
×
55
}
×
56

57
// Returns the root scope
58
func (ss *ScopeStack) GlobalScope() *Scope {
2✔
59
        scope := ss.current
2✔
60
        for scope.Parent != nil {
2✔
61
                scope = scope.Parent
×
62
        }
×
63
        return scope
2✔
64
}
65

66
// LookupVariableType looks up a variable's type in the current scope stack
NEW
67
func (ss *ScopeStack) LookupVariableType(name ast.Identifier) ([]ast.TypeNode, bool) {
×
NEW
68
        // Start from the current scope and work up through parents
×
NEW
69
        scope := ss.current
×
NEW
70
        for scope != nil {
×
NEW
71
                if types, exists := scope.LookupVariableType(name); exists {
×
NEW
72
                        return types, true
×
NEW
73
                }
×
NEW
74
                scope = scope.Parent
×
75
        }
NEW
76
        return nil, false
×
77
}
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