EnsureDecl ensures that every predicate in the program is declared. It also ensures consistency of temporal usage.
(clauses []ast.Clause)
| 215 | // EnsureDecl ensures that every predicate in the program is declared. |
| 216 | // It also ensures consistency of temporal usage. |
| 217 | func (a *Analyzer) EnsureDecl(clauses []ast.Clause) error { |
| 218 | extraByName := byName(a.extraPredicates) |
| 219 | declByName := byName(a.decl) |
| 220 | for _, c := range clauses { |
| 221 | pred := c.Head.Predicate |
| 222 | name := pred.Symbol |
| 223 | // Check that the name was not defined previously (in a separate source). |
| 224 | // We may permit "distributing" definitions over source files later. |
| 225 | if decl, ok := a.extraPredicates[pred]; ok { |
| 226 | if decl.IsExtensional() && len(c.Premises) == 0 { |
| 227 | continue |
| 228 | } |
| 229 | return fmt.Errorf("predicate %v was defined previously %v", decl.DeclaredAtom.Predicate, decl) |
| 230 | } |
| 231 | if decl, ok := extraByName[name]; ok { // different arity |
| 232 | return fmt.Errorf( |
| 233 | "predicate %v was defined previously", decl.DeclaredAtom.Predicate) |
| 234 | } |
| 235 | |
| 236 | // If we already have a declaration, check if it is compatible. |
| 237 | // Note that we may have multiple declarations for the same predicate |
| 238 | // (e.g. one from use and one from package). |
| 239 | if decl, ok := a.decl[pred]; ok { |
| 240 | // If we have an existing declaration, check for temporal consistency |
| 241 | if c.HeadTime != nil && !c.HeadTime.IsEternal() { |
| 242 | if !decl.IsTemporal() && !decl.IsMaybeTemporal() { |
| 243 | return fmt.Errorf("predicate %v is not declared temporal but used with temporal annotation in %v", pred, c) |
| 244 | } |
| 245 | } |
| 246 | continue |
| 247 | } |
| 248 | // Check that the name was not defined in the same source with a different arity. |
| 249 | if decl, ok := declByName[name]; ok { |
| 250 | return fmt.Errorf("%v does not match arity of %v", c.Head, decl.DeclaredAtom) |
| 251 | } |
| 252 | |
| 253 | var ( |
| 254 | synthDecl ast.Decl |
| 255 | err error |
| 256 | ) |
| 257 | if c.Premises != nil { |
| 258 | synthDecl, err = ast.NewSyntheticDecl(c.Head) // preserve variable names. |
| 259 | } else { |
| 260 | synthDecl = ast.NewSyntheticDeclFromSym(pred) |
| 261 | } |
| 262 | if err != nil { |
| 263 | return err |
| 264 | } |
| 265 | |
| 266 | // If this is a synthetic declaration and we have a temporal annotation, |
| 267 | // mark it as "MaybeTemporal" so we can check consistency later. |
| 268 | if c.HeadTime != nil && !c.HeadTime.IsEternal() { |
| 269 | synthDecl.Descr = append(synthDecl.Descr, ast.NewAtom(ast.DescrMaybeTemporal)) |
| 270 | } |
| 271 | |
| 272 | a.decl[pred] = synthDecl |
| 273 | declByName[pred.Symbol] = a.decl[pred] |
| 274 | } |
no test coverage detected