diff --git a/parser/ast.go b/parser/ast.go index 0e401f7..c89bf5e 100644 --- a/parser/ast.go +++ b/parser/ast.go @@ -353,9 +353,11 @@ func (fp *FunctionParameter) Pos() Position { return fp.Position } // Identifier represents variable references and names. type Identifier struct { - Value string - typeInfo TypeInfo - Position Position + Value string + ScopeDepth int // 0 = global, 1+ = local depth + SlotIndex int // register/stack slot (-1 = unresolved) + typeInfo TypeInfo + Position Position } func (i *Identifier) expressionNode() {} @@ -366,7 +368,8 @@ func (i *Identifier) TypeInfo() 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. type NumberLiteral struct { @@ -418,11 +421,14 @@ func (nl *NilLiteral) Pos() Position { return nl.Position } // FunctionLiteral represents function definitions with parameters, body, and optional return type. type FunctionLiteral struct { - Parameters []FunctionParameter - Body []Statement - ReturnType TypeInfo - Variadic bool - Position Position + Parameters []FunctionParameter + Body []Statement + ReturnType TypeInfo + Variadic bool + LocalCount int // Pre-computed local variable count + UpvalueCount int // Number of captured variables + MaxStackDepth int // Maximum expression evaluation depth + Position Position } func (fl *FunctionLiteral) expressionNode() {} diff --git a/parser/parser.go b/parser/parser.go index 351a8dd..84443e4 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -31,9 +31,11 @@ type Parser struct { errors []ParseError - // Scope tracking - scopes []map[string]bool - scopeTypes []string + // Scope tracking with slot management + scopes []map[string]*Variable + scopeTypes []string + scopeSlots []int // Next available slot per scope + currentDepth int // Struct tracking with ID mapping structs map[string]*StructStatement @@ -41,16 +43,26 @@ type Parser struct { 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 func NewParser(lexer *Lexer) *Parser { p := &Parser{ - lexer: lexer, - errors: []ParseError{}, - scopes: []map[string]bool{make(map[string]bool)}, - scopeTypes: []string{"global"}, - structs: make(map[string]*StructStatement), - structIDs: make(map[uint16]*StructStatement), - nextID: 1, // 0 reserved for non-struct types + lexer: lexer, + errors: []ParseError{}, + scopes: []map[string]*Variable{make(map[string]*Variable)}, + scopeTypes: []string{"global"}, + scopeSlots: []int{0}, + currentDepth: 0, + structs: make(map[string]*StructStatement), + structIDs: make(map[uint16]*StructStatement), + nextID: 1, // 0 reserved for non-struct types } p.prefixParseFns = make(map[TokenType]func() Expression) @@ -113,20 +125,24 @@ func (p *Parser) isStructDefined(name string) bool { return exists } -// Scope management +// Scope management with slot allocation 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.scopeSlots = append(p.scopeSlots, 0) + p.currentDepth++ } func (p *Parser) exitScope() { if len(p.scopes) > 1 { p.scopes = p.scopes[:len(p.scopes)-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" { 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 { for i := len(p.scopes) - 1; i >= 0; i-- { - if p.scopes[i][name] { + if _, exists := p.scopes[i][name]; exists { return true } } return false } -func (p *Parser) declareVariable(name string) { - p.currentVariableScope()[name] = true +func (p *Parser) declareVariable(name string, typeHint TypeInfo) *Variable { + 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) { - p.scopes[len(p.scopes)-1][name] = true +func (p *Parser) declareLoopVariable(name string, typeHint TypeInfo) *Variable { + 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 @@ -381,7 +433,7 @@ func (p *Parser) parseFunctionStatement() Statement { p.enterScope("function") for _, param := range funcLit.Parameters { - p.declareVariable(param.Name) + p.declareVariable(param.Name, param.TypeHint) } funcLit.Body = p.parseBlockStatements(END) p.exitScope() @@ -436,9 +488,17 @@ func (p *Parser) parseIdentifierStatement() Statement { // Validate assignment target and check if it's a declaration switch target := expr.(type) { case *Identifier: - assignment.IsDeclaration = !p.isVariableDeclared(target.Value) - if assignment.IsDeclaration { - p.declareVariable(target.Value) + if variable := p.lookupVariable(target.Value); variable != nil { + // Existing variable - resolve it + 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: assignment.IsDeclaration = false @@ -626,7 +686,12 @@ func (p *Parser) parseNumericForStatement(variable *Identifier, pos Position) *F p.nextToken() 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) p.exitScope() @@ -677,10 +742,20 @@ func (p *Parser) parseForInStatement(firstVar *Identifier, pos Position) *ForInS p.nextToken() p.enterScope("loop") + + // Declare and resolve loop variables 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) p.exitScope() @@ -806,7 +881,21 @@ func (p *Parser) ParseExpression(precedence Precedence) Expression { // Expression parsing functions 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 { @@ -947,9 +1036,17 @@ func (p *Parser) parseParenthesizedAssignment() Expression { // Handle variable declaration for assignment expressions if ident, ok := target.(*Identifier); ok { - assignExpr.IsDeclaration = !p.isVariableDeclared(ident.Value) - if assignExpr.IsDeclaration { - p.declareVariable(ident.Value) + if variable := p.lookupVariable(ident.Value); variable != nil { + // Existing variable + 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.enterScope("function") + + // Declare function parameters as resolved variables 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) + + // 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() if !p.curTokenIs(END) {