package interpreter import ( "fmt" "masonry/lang" "strings" ) type ProtoInterpreter struct { entities map[string]*lang.Entity endpoints map[string]*lang.Endpoint server *lang.Server } func NewProtoInterpreter() *ProtoInterpreter { return &ProtoInterpreter{ entities: make(map[string]*lang.Entity), endpoints: make(map[string]*lang.Endpoint), } } func (pi *ProtoInterpreter) Interpret(ast lang.AST) error { for _, def := range ast.Definitions { if def.Server != nil { pi.server = def.Server } else if def.Entity != nil { pi.entities[def.Entity.Name] = def.Entity } else if def.Endpoint != nil { key := fmt.Sprintf("%s_%s", def.Endpoint.Method, strings.ReplaceAll(def.Endpoint.Path, "/", "_")) pi.endpoints[key] = def.Endpoint } } // Validate references for _, endpoint := range pi.endpoints { if endpoint.Entity != nil { if _, exists := pi.entities[*endpoint.Entity]; !exists { return fmt.Errorf("undefined entity referenced in endpoint request: %s", *endpoint.Entity) } } if endpoint.Response != nil { entity, exists := pi.entities[*endpoint.Entity] if !exists { return fmt.Errorf("undefined entity referenced in endpoint response: %s", *endpoint.Entity) } // validate the fields of the response for _, field := range endpoint.Response.Fields { // check for a field with the same name in the entity found := false for _, entityField := range entity.Fields { if entityField.Name == field { found = true break } } if !found { return fmt.Errorf("undefined field referenced in endpoint response: %s", field) } } } } return nil }