128 lines
3.7 KiB
Go
128 lines
3.7 KiB
Go
package analyzer
|
|
|
|
import "github.com/alecthomas/participle/v2"
|
|
import "github.com/alecthomas/participle/v2/lexer"
|
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
|
import "git.tebibyte.media/sashakoshka/fspl/parser"
|
|
|
|
// Tree is a semantic tree. It contains the same constructs as the syntax tree,
|
|
// but with their semantic information filled in.
|
|
type Tree struct {
|
|
scopeContextManager
|
|
|
|
rawTypes map[string] *entity.Typedef
|
|
rawFunctions map[string] *entity.Function
|
|
rawMethods map[string] *entity.Method
|
|
|
|
ast parser.Tree
|
|
incompleteTypes map[string] *entity.Typedef
|
|
|
|
Types map[string] *entity.Typedef
|
|
Functions map[string] *entity.Function
|
|
}
|
|
|
|
// Analyze takes in an AST and analyzes its contents within the context of this
|
|
// semantic tree. Analyzed entities will be added to the tree.
|
|
func (this *Tree) Analyze (ast parser.Tree) error {
|
|
this.ensure()
|
|
this.ast = ast
|
|
err := this.assembleRawMaps()
|
|
if err != nil { return err }
|
|
return this.analyzeDeclarations()
|
|
}
|
|
|
|
func (this *Tree) assembleRawMaps () error {
|
|
for _, declaration := range this.ast.Declarations {
|
|
switch declaration.(type) {
|
|
case *entity.Typedef:
|
|
ty := declaration.(*entity.Typedef)
|
|
err := this.topLevelNameAvailable(ty.Pos, ty.Name)
|
|
if err != nil { return err }
|
|
ty.Methods = make(map[string] *entity.Method)
|
|
this.rawTypes[ty.Name] = ty
|
|
case *entity.Function:
|
|
function := declaration.(*entity.Function)
|
|
err := this.topLevelNameAvailable (
|
|
function.Pos,
|
|
function.Signature.Name)
|
|
if err != nil { return err }
|
|
this.rawFunctions[function.Signature.Name] = function
|
|
case *entity.Method:
|
|
method := declaration.(*entity.Method)
|
|
name := method.TypeName + "." + method.Signature.Name
|
|
err := this.topLevelNameAvailable(method.Pos, name)
|
|
if err != nil { return err }
|
|
this.rawMethods[name] = method
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (this *Tree) topLevelNameAvailable (currentPos lexer.Position, name string) error {
|
|
if _, isPrimitive := primitiveTypes[name]; isPrimitive {
|
|
return participle.Errorf (
|
|
currentPos, "cannot shadow primitive %s",
|
|
name)
|
|
}
|
|
if _, isBuiltin := builtinTypes[name]; isBuiltin {
|
|
return participle.Errorf (
|
|
currentPos, "cannot shadow builtin %s",
|
|
name)
|
|
}
|
|
if ty, isType := this.rawTypes[name]; isType {
|
|
return participle.Errorf (
|
|
currentPos, "%s already declared at %v",
|
|
name, ty.Pos)
|
|
}
|
|
if function, isFunction := this.rawFunctions[name]; isFunction {
|
|
return participle.Errorf (
|
|
currentPos, "%s already declared at %v",
|
|
name, function.Pos)
|
|
}
|
|
if method, isMethod := this.rawMethods[name]; isMethod {
|
|
return participle.Errorf (
|
|
currentPos, "%s already declared at %v",
|
|
name, method.Pos)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (this *Tree) analyzeDeclarations () error {
|
|
for name, rawType := range this.rawTypes {
|
|
ty, err := this.analyzeTypedef(rawType.Pos, name, false)
|
|
if err != nil { return err }
|
|
this.Types[name] = ty
|
|
}
|
|
for name, rawFunction := range this.rawFunctions {
|
|
_, err := this.analyzeFunction(rawFunction.Pos, name)
|
|
if err != nil { return err }
|
|
}
|
|
for _, rawMethod := range this.rawMethods {
|
|
_, err := this.analyzeMethod (
|
|
rawMethod.Pos,
|
|
rawMethod.TypeName,
|
|
rawMethod.Signature.Name)
|
|
if err != nil { return err }
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (this *Tree) ensure () {
|
|
if this.rawTypes != nil { return }
|
|
this.rawTypes = make(map[string] *entity.Typedef)
|
|
this.rawFunctions = make(map[string] *entity.Function)
|
|
this.rawMethods = make(map[string] *entity.Method)
|
|
this.incompleteTypes = make(map[string] *entity.Typedef)
|
|
this.Types = make(map[string] *entity.Typedef)
|
|
this.Functions = make(map[string] *entity.Function)
|
|
|
|
for name, ty := range builtinTypes {
|
|
access := entity.AccessPublic
|
|
this.Types[name] = &entity.Typedef {
|
|
Acc: &access,
|
|
Name: name,
|
|
Type: ty,
|
|
}
|
|
}
|
|
}
|