entity.Key now has an optional method field

This commit is contained in:
Sasha Koshka 2024-02-19 12:05:13 -05:00
parent 4166fb8817
commit ff18aae2b6
3 changed files with 72 additions and 66 deletions

View File

@ -4,37 +4,29 @@ import "fmt"
import "git.tebibyte.media/sashakoshka/fspl/errors"
import "git.tebibyte.media/sashakoshka/fspl/entity"
func (this *Tree) methodKey (typeKey entity.Key, name string) entity.Key {
return entity.Key {
Unit: typeKey.Unit,
Name: typeKey.Name + "." + name,
}
}
// analyzeMethod analyzes a method that is directly owned by the specified type.
func (this *Tree) analyzeMethod (
pos errors.Position,
typeKey entity.Key,
name string,
pos errors.Position,
key entity.Key,
) (
*entity.Method,
error,
) {
// get parent typedef
typeKey := key.StripMethod()
owner, err := this.analyzeTypedef(pos, typeKey, false)
if err != nil { return nil, err }
// return if exists already
if method, exists := owner.Methods[name]; exists {
if method, exists := owner.Methods[key.Method]; exists {
return method, nil
}
// error if method is missing
method, exists := this.rawMethods[this.methodKey(typeKey, name)]
method, exists := this.rawMethods[key]
if !exists {
return nil, errors.Errorf (
pos, "no method named %s.%s",
typeKey.Name, name)
return nil, errors.Errorf(pos, "no method named %v", key)
}
// set method's unit, very important information yes
@ -72,8 +64,9 @@ func (this *Tree) analyzeMethod (
Position: method.Position,
Referenced: &entity.TypeNamed {
Position: method.Position,
Name: typeKey.Name,
Type: owner.Type,
Unt: key.Unit,
Name: key.Name,
Type: owner.Type,
},
},
}
@ -82,7 +75,7 @@ func (this *Tree) analyzeMethod (
// add incomplete method to complete methods because there is enough
// information for it to be complete from the point of view of other
// parts of the code
owner.Methods[name] = method
owner.Methods[key.Method] = method
// analyze method body
if method.Body != nil {
@ -124,12 +117,13 @@ func (this *Tree) analyzeMethodOrBehaviorInternal (
switch ty.(type) {
case *entity.TypeNamed:
ty := ty.(*entity.TypeNamed)
typeKey := entity.Key {
Unit: ty.Type.Unit(),
Name: ty.Name,
key := entity.Key {
Unit: ty.Type.Unit(),
Name: ty.Name,
Method: name,
}
if this.methodExists(this.methodKey(typeKey, name)) {
method, err := this.analyzeMethod(pos, typeKey, name)
if this.methodExists(key) {
method, err := this.analyzeMethod(pos, key)
if err != nil { return nil, err }
return method, nil
} else {

View File

@ -40,69 +40,65 @@ func (this *Tree) Analyze (
func (this *Tree) assembleRawMaps () error {
for _, declaration := range this.ast.Declarations {
switch declaration.(type) {
switch declaration := declaration.(type) {
case *entity.Typedef:
ty := declaration.(*entity.Typedef)
err := this.topLevelNameAvailable(ty.Position, ty.Name)
if err != nil { return err }
ty.Methods = make(map[string] *entity.Method)
this.rawTypes[entity.Key {
key := entity.Key {
Unit: this.unit,
Name: ty.Name,
}] = ty
Name: declaration.Name,
}
err := this.topLevelNameAvailable(declaration.Position, key)
if err != nil { return err }
declaration.Methods = make(map[string] *entity.Method)
this.rawTypes[key] = declaration
case *entity.Function:
function := declaration.(*entity.Function)
err := this.topLevelNameAvailable (
function.Position,
function.Signature.Name)
if err != nil { return err }
this.rawFunctions[entity.Key {
key := entity.Key {
Unit: this.unit,
Name: function.Signature.Name,
}] = function
Name: declaration.Signature.Name,
}
err := this.topLevelNameAvailable(declaration.Position, key)
if err != nil { return err }
this.rawFunctions[key] = declaration
case *entity.Method:
method := declaration.(*entity.Method)
name := method.TypeName + "." + method.Signature.Name
err := this.topLevelNameAvailable(method.Position, name)
key := entity.Key {
Unit: this.unit,
Name: declaration.TypeName,
Method: declaration.Signature.Name,
}
err := this.topLevelNameAvailable(declaration.Position, key)
if err != nil { return err }
this.rawMethods[entity.Key {
Unit: this.unit,
Name: name,
}] = method
this.rawMethods[key] = declaration
}
}
return nil
}
func (this *Tree) topLevelNameAvailable (currentPos errors.Position, name string) error {
if _, isPrimitive := primitiveTypes[name]; isPrimitive {
func (this *Tree) topLevelNameAvailable (currentPos errors.Position, key entity.Key) error {
if _, isPrimitive := primitiveTypes[key.Name]; isPrimitive {
return errors.Errorf (
currentPos, "cannot shadow primitive %s",
name)
key.Name)
}
if _, isBuiltin := builtinTypes[name]; isBuiltin {
if _, isBuiltin := builtinTypes[key.Name]; isBuiltin {
return errors.Errorf (
currentPos, "cannot shadow builtin %s",
name)
}
key := entity.Key {
Unit: this.unit,
Name: name,
key.Name)
}
if ty, isType := this.rawTypes[key]; isType {
return errors.Errorf (
currentPos, "%s already declared at %v",
name, ty.Position)
key.Name, ty.Position)
}
if function, isFunction := this.rawFunctions[key]; isFunction {
return errors.Errorf (
currentPos, "%s already declared at %v",
name, function.Position)
key.Name, function.Position)
}
if method, isMethod := this.rawMethods[key]; isMethod {
return errors.Errorf (
currentPos, "%s already declared at %v",
name, method.Position)
currentPos, "%s.%s already declared at %v",
key.Name, key.Method, method.Position)
}
return nil
}
@ -121,10 +117,10 @@ func (this *Tree) analyzeDeclarations () error {
_, err := this.analyzeMethod (
rawMethod.Position,
entity.Key {
Unit: this.unit,
Name: rawMethod.TypeName,
},
rawMethod.Signature.Name)
Unit: this.unit,
Name: rawMethod.TypeName,
Method: rawMethod.Signature.Name,
})
if err != nil { return err }
}
return nil

View File

@ -7,22 +7,38 @@ import "git.tebibyte.media/sashakoshka/fspl/errors"
// Key globally indexes top level entities in contexts where modules matter.
type Key struct {
Unit uuid.UUID
Name string
Unit uuid.UUID
Name string
Method string
}
func (key Key) String () string {
return fmt.Sprintf("%v::%v", key.Unit, key.Name)
out := fmt.Sprintf("%v::%v", key.Unit, key.Name)
if key.Method != "" {
out = fmt.Sprintf("%s.%s", out, key.Method)
}
return out
}
// LinkName returns the name that the entity it refers to will be given when
// compiled.
func (key Key) LinkName () string {
data := [16]byte(key.Unit)
return fmt.Sprintf(
out := fmt.Sprintf(
"%s::%s",
base64.StdEncoding.EncodeToString(data[:]),
key.Name)
if key.Method != "" {
out = fmt.Sprintf("%s.%s", out, key.Method)
}
return out
}
// StripMethod returns a copy of the key that refers to a type instead of a
// method.
func (key Key) StripMethod () Key {
key.Method = ""
return key
}
// TopLevel is any construct that is placed at the root of a file.