symbol pre-resolution

This commit is contained in:
Sky Johnson 2025-06-11 23:19:54 -05:00
parent 3d07d010dc
commit 6575b077fe
2 changed files with 153 additions and 39 deletions

View File

@ -354,6 +354,8 @@ func (fp *FunctionParameter) Pos() Position { return fp.Position }
// Identifier represents variable references and names. // Identifier represents variable references and names.
type Identifier struct { type Identifier struct {
Value string Value string
ScopeDepth int // 0 = global, 1+ = local depth
SlotIndex int // register/stack slot (-1 = unresolved)
typeInfo TypeInfo typeInfo TypeInfo
Position Position Position Position
} }
@ -367,6 +369,7 @@ func (i *Identifier) TypeInfo() TypeInfo {
return i.typeInfo return i.typeInfo
} }
func (i *Identifier) Pos() Position { return i.Position } func (i *Identifier) Pos() Position { return i.Position }
func (i *Identifier) IsResolved() bool { return i.SlotIndex >= 0 }
// NumberLiteral represents numeric constants including integers, floats, hex, and binary. // NumberLiteral represents numeric constants including integers, floats, hex, and binary.
type NumberLiteral struct { type NumberLiteral struct {
@ -422,6 +425,9 @@ type FunctionLiteral struct {
Body []Statement Body []Statement
ReturnType TypeInfo ReturnType TypeInfo
Variadic bool Variadic bool
LocalCount int // Pre-computed local variable count
UpvalueCount int // Number of captured variables
MaxStackDepth int // Maximum expression evaluation depth
Position Position Position Position
} }

View File

@ -31,9 +31,11 @@ type Parser struct {
errors []ParseError errors []ParseError
// Scope tracking // Scope tracking with slot management
scopes []map[string]bool scopes []map[string]*Variable
scopeTypes []string scopeTypes []string
scopeSlots []int // Next available slot per scope
currentDepth int
// Struct tracking with ID mapping // Struct tracking with ID mapping
structs map[string]*StructStatement structs map[string]*StructStatement
@ -41,13 +43,23 @@ type Parser struct {
nextID uint16 nextID uint16
} }
// Variable represents a resolved variable in scope
type Variable struct {
Name string
ScopeDepth int
SlotIndex int
TypeHint TypeInfo
}
// NewParser creates a new parser instance // NewParser creates a new parser instance
func NewParser(lexer *Lexer) *Parser { func NewParser(lexer *Lexer) *Parser {
p := &Parser{ p := &Parser{
lexer: lexer, lexer: lexer,
errors: []ParseError{}, errors: []ParseError{},
scopes: []map[string]bool{make(map[string]bool)}, scopes: []map[string]*Variable{make(map[string]*Variable)},
scopeTypes: []string{"global"}, scopeTypes: []string{"global"},
scopeSlots: []int{0},
currentDepth: 0,
structs: make(map[string]*StructStatement), structs: make(map[string]*StructStatement),
structIDs: make(map[uint16]*StructStatement), structIDs: make(map[uint16]*StructStatement),
nextID: 1, // 0 reserved for non-struct types nextID: 1, // 0 reserved for non-struct types
@ -113,20 +125,24 @@ func (p *Parser) isStructDefined(name string) bool {
return exists return exists
} }
// Scope management // Scope management with slot allocation
func (p *Parser) enterScope(scopeType string) { func (p *Parser) enterScope(scopeType string) {
p.scopes = append(p.scopes, make(map[string]bool)) p.scopes = append(p.scopes, make(map[string]*Variable))
p.scopeTypes = append(p.scopeTypes, scopeType) p.scopeTypes = append(p.scopeTypes, scopeType)
p.scopeSlots = append(p.scopeSlots, 0)
p.currentDepth++
} }
func (p *Parser) exitScope() { func (p *Parser) exitScope() {
if len(p.scopes) > 1 { if len(p.scopes) > 1 {
p.scopes = p.scopes[:len(p.scopes)-1] p.scopes = p.scopes[:len(p.scopes)-1]
p.scopeTypes = p.scopeTypes[:len(p.scopeTypes)-1] p.scopeTypes = p.scopeTypes[:len(p.scopeTypes)-1]
p.scopeSlots = p.scopeSlots[:len(p.scopeSlots)-1]
p.currentDepth--
} }
} }
func (p *Parser) currentVariableScope() map[string]bool { func (p *Parser) currentVariableScope() map[string]*Variable {
if len(p.scopeTypes) > 1 && p.scopeTypes[len(p.scopeTypes)-1] == "loop" { if len(p.scopeTypes) > 1 && p.scopeTypes[len(p.scopeTypes)-1] == "loop" {
return p.scopes[len(p.scopes)-2] return p.scopes[len(p.scopes)-2]
} }
@ -135,19 +151,55 @@ func (p *Parser) currentVariableScope() map[string]bool {
func (p *Parser) isVariableDeclared(name string) bool { func (p *Parser) isVariableDeclared(name string) bool {
for i := len(p.scopes) - 1; i >= 0; i-- { for i := len(p.scopes) - 1; i >= 0; i-- {
if p.scopes[i][name] { if _, exists := p.scopes[i][name]; exists {
return true return true
} }
} }
return false return false
} }
func (p *Parser) declareVariable(name string) { func (p *Parser) declareVariable(name string, typeHint TypeInfo) *Variable {
p.currentVariableScope()[name] = true scope := p.currentVariableScope()
scopeIdx := len(p.scopes) - 1
if len(p.scopeTypes) > 1 && p.scopeTypes[len(p.scopeTypes)-1] == "loop" {
scopeIdx--
}
variable := &Variable{
Name: name,
ScopeDepth: p.currentDepth,
SlotIndex: p.scopeSlots[scopeIdx],
TypeHint: typeHint,
}
scope[name] = variable
p.scopeSlots[scopeIdx]++
return variable
} }
func (p *Parser) declareLoopVariable(name string) { func (p *Parser) declareLoopVariable(name string, typeHint TypeInfo) *Variable {
p.scopes[len(p.scopes)-1][name] = true scope := p.scopes[len(p.scopes)-1]
scopeIdx := len(p.scopes) - 1
variable := &Variable{
Name: name,
ScopeDepth: p.currentDepth,
SlotIndex: p.scopeSlots[scopeIdx],
TypeHint: typeHint,
}
scope[name] = variable
p.scopeSlots[scopeIdx]++
return variable
}
func (p *Parser) lookupVariable(name string) *Variable {
for i := len(p.scopes) - 1; i >= 0; i-- {
if variable, exists := p.scopes[i][name]; exists {
return variable
}
}
return nil
} }
// parseTypeHint parses optional type hint after colon, returns by value // parseTypeHint parses optional type hint after colon, returns by value
@ -381,7 +433,7 @@ func (p *Parser) parseFunctionStatement() Statement {
p.enterScope("function") p.enterScope("function")
for _, param := range funcLit.Parameters { for _, param := range funcLit.Parameters {
p.declareVariable(param.Name) p.declareVariable(param.Name, param.TypeHint)
} }
funcLit.Body = p.parseBlockStatements(END) funcLit.Body = p.parseBlockStatements(END)
p.exitScope() p.exitScope()
@ -436,9 +488,17 @@ func (p *Parser) parseIdentifierStatement() Statement {
// Validate assignment target and check if it's a declaration // Validate assignment target and check if it's a declaration
switch target := expr.(type) { switch target := expr.(type) {
case *Identifier: case *Identifier:
assignment.IsDeclaration = !p.isVariableDeclared(target.Value) if variable := p.lookupVariable(target.Value); variable != nil {
if assignment.IsDeclaration { // Existing variable - resolve it
p.declareVariable(target.Value) target.ScopeDepth = variable.ScopeDepth
target.SlotIndex = variable.SlotIndex
assignment.IsDeclaration = false
} else {
// New variable declaration - create and resolve
variable := p.declareVariable(target.Value, typeHint)
target.ScopeDepth = variable.ScopeDepth
target.SlotIndex = variable.SlotIndex
assignment.IsDeclaration = true
} }
case *DotExpression, *IndexExpression: case *DotExpression, *IndexExpression:
assignment.IsDeclaration = false assignment.IsDeclaration = false
@ -626,7 +686,12 @@ func (p *Parser) parseNumericForStatement(variable *Identifier, pos Position) *F
p.nextToken() p.nextToken()
p.enterScope("loop") p.enterScope("loop")
p.declareLoopVariable(variable.Value) // Declare and resolve loop variable
loopVar := p.declareLoopVariable(variable.Value, NumberType)
variable.ScopeDepth = loopVar.ScopeDepth
variable.SlotIndex = loopVar.SlotIndex
variable.typeInfo = NumberType
stmt.Body = p.parseBlockStatements(END) stmt.Body = p.parseBlockStatements(END)
p.exitScope() p.exitScope()
@ -677,10 +742,20 @@ func (p *Parser) parseForInStatement(firstVar *Identifier, pos Position) *ForInS
p.nextToken() p.nextToken()
p.enterScope("loop") p.enterScope("loop")
// Declare and resolve loop variables
if stmt.Key != nil { if stmt.Key != nil {
p.declareLoopVariable(stmt.Key.Value) keyVar := p.declareLoopVariable(stmt.Key.Value, AnyType)
stmt.Key.ScopeDepth = keyVar.ScopeDepth
stmt.Key.SlotIndex = keyVar.SlotIndex
stmt.Key.typeInfo = AnyType
} }
p.declareLoopVariable(stmt.Value.Value)
valueVar := p.declareLoopVariable(stmt.Value.Value, AnyType)
stmt.Value.ScopeDepth = valueVar.ScopeDepth
stmt.Value.SlotIndex = valueVar.SlotIndex
stmt.Value.typeInfo = AnyType
stmt.Body = p.parseBlockStatements(END) stmt.Body = p.parseBlockStatements(END)
p.exitScope() p.exitScope()
@ -806,7 +881,21 @@ func (p *Parser) ParseExpression(precedence Precedence) Expression {
// Expression parsing functions // Expression parsing functions
func (p *Parser) parseIdentifier() Expression { func (p *Parser) parseIdentifier() Expression {
return &Identifier{Value: p.curToken.Literal, Position: p.pos()} ident := &Identifier{
Value: p.curToken.Literal,
ScopeDepth: -1,
SlotIndex: -1,
Position: p.pos(),
}
// Resolve variable if it exists
if variable := p.lookupVariable(ident.Value); variable != nil {
ident.ScopeDepth = variable.ScopeDepth
ident.SlotIndex = variable.SlotIndex
ident.typeInfo = variable.TypeHint
}
return ident
} }
func (p *Parser) parseNumberLiteral() Expression { func (p *Parser) parseNumberLiteral() Expression {
@ -947,9 +1036,17 @@ func (p *Parser) parseParenthesizedAssignment() Expression {
// Handle variable declaration for assignment expressions // Handle variable declaration for assignment expressions
if ident, ok := target.(*Identifier); ok { if ident, ok := target.(*Identifier); ok {
assignExpr.IsDeclaration = !p.isVariableDeclared(ident.Value) if variable := p.lookupVariable(ident.Value); variable != nil {
if assignExpr.IsDeclaration { // Existing variable
p.declareVariable(ident.Value) ident.ScopeDepth = variable.ScopeDepth
ident.SlotIndex = variable.SlotIndex
assignExpr.IsDeclaration = false
} else {
// New variable declaration
newVar := p.declareVariable(ident.Value, UnknownType)
ident.ScopeDepth = newVar.ScopeDepth
ident.SlotIndex = newVar.SlotIndex
assignExpr.IsDeclaration = true
} }
} }
@ -977,10 +1074,21 @@ func (p *Parser) parseFunctionLiteral() Expression {
p.nextToken() p.nextToken()
p.enterScope("function") p.enterScope("function")
// Declare function parameters as resolved variables
for _, param := range fn.Parameters { for _, param := range fn.Parameters {
p.declareVariable(param.Name) p.declareVariable(param.Name, param.TypeHint)
param.Position = Position{Line: p.curToken.Line, Column: p.curToken.Column}
} }
fn.Body = p.parseBlockStatements(END) fn.Body = p.parseBlockStatements(END)
// Calculate function metadata before exiting scope
scopeIdx := len(p.scopes) - 1
fn.LocalCount = p.scopeSlots[scopeIdx]
fn.UpvalueCount = 0 // TODO: Calculate captured variables
fn.MaxStackDepth = 0 // TODO: Calculate max expression depth
p.exitScope() p.exitScope()
if !p.curTokenIs(END) { if !p.curTokenIs(END) {