symbol pre-resolution
This commit is contained in:
parent
3d07d010dc
commit
6575b077fe
@ -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() {}
|
||||
|
168
parser/parser.go
168
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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user