All files

src/compiler/source_inventory.panack

Green: covered; red: known zero; amber: unavailable. Blank lines are outside the executable-start-line denominator.

    1 import "source_maps.panack"
    2 
    3 // IDs are structural paths within a source snapshot, never emitted PCs. The
    4 // exact snapshot/artifact/compiler envelope is part of every ID's identity.
    5 record InventoryItem {
    6   id: Str,
    7   kind: Str,
    8   detail: Str,
    9   span: SourceSpan
   10 }
   11 
   12 pure inventory_item(id: Str, kind: Str, detail: Str, expression: Expr): [InventoryItem] {
   13   match expression_span(expression) {
   14     Some(span) => [InventoryItem(id, kind, detail, span)],
   15     None() => []
   16   }
   17 }
   18 
   19 pure inventory_decision(id: Str, kind: Str, expression: Expr, outcomes: [Str]): [InventoryItem] {
   20   mut items: [InventoryItem] = inventory_item(id, "decision", kind, expression)
   21   for outcome in outcomes {
   22     items = concat(items, inventory_item(id + "/" + outcome, "outcome", outcome, expression))
   23   }
   24   items
   25 }
   26 
   27 pure inventory_expressions(values: [Expr], id: Str): [InventoryItem] {
   28   mut items: [InventoryItem] = []
   29   mut index: Nat = 0
   30   for value in values {
   31     items = concat(items, inventory_expression(value, id + "/${index}"))
   32     index = index + 1
   33   }
   34   items
   35 }
   36 
   37 pure inventory_expression(expression: Expr, id: Str): [InventoryItem] {
   38   mut items: [InventoryItem] = inventory_item(id, "expression", "attempt", expression)
   39   match unlocated_expression(expression) {
   40     LocatedExpr(span, value) => {},
   41     NatExpr(value) => {}, DecimalExpr(value) => {}, StringExpr(value) => {},
   42     BoolExpr(value) => {}, NameExpr(value) => {}, FunctionExpr(value) => {},
   43     ArrayExpr(values) => { items = concat(items, inventory_expressions(values, id)); },
   44     UnaryExpr(operator, value) => { items = concat(items, inventory_expression(value, id + "/operand")); },
   45     BinaryExpr(operator, left, right) => {
   46       if operator == "&&" || operator == "||" {
   47         items = concat(items, inventory_decision(id + "/decision", operator, left, ["evaluate-right", "skip-right"]))
   48       }
   49       items = concat(items, inventory_expression(left, id + "/left"))
   50       items = concat(items, inventory_expression(right, id + "/right"))
   51     },
   52     CallExpr(name, arguments, types) => { items = concat(items, inventory_expressions(arguments, id + "/args")); },
   53     DotCallExpr(target, name, arguments, types) => {
   54       items = concat(items, inventory_expression(target, id + "/receiver"))
   55       items = concat(items, inventory_expressions(arguments, id + "/args"))
   56     },
   57     FieldExpr(target, name) => { items = concat(items, inventory_expression(target, id + "/receiver")); },
   58     IndexExpr(target, index) => {
   59       items = concat(items, inventory_expression(target, id + "/receiver"))
   60       items = concat(items, inventory_expression(index, id + "/index"))
   61     },
   62     IfExpr(condition, yes, no, has_else) => {
   63       items = concat(items, inventory_decision(id + "/decision", "if", condition, ["true", "false"]))
   64       items = concat(items, inventory_expression(condition, id + "/condition"))
   65       items = concat(items, inventory_block(yes, id + "/true"))
   66       items = concat(items, inventory_block(no, id + "/false"))
   67     },
   68     BlockExpr(block) => { items = concat(items, inventory_block(block, id + "/block")); },
   69     MatchExpr(subject, arms) => {
   70       items = concat(items, inventory_item(id + "/decision", "decision", "match", subject))
   71       items = concat(items, inventory_expression(subject, id + "/subject"))
   72       mut index: Nat = 0
   73       for arm in arms {
   74         arm_id: Str = id + "/arm/${index}"
   75         items = concat(items, inventory_item(arm_id, "outcome", arm.pattern.variant, arm.body))
   76         items = concat(items, inventory_expression(arm.body, arm_id + "/body"))
   77         index = index + 1
   78       }
   79     }
   80   }
   81   items
   82 }
   83 
   84 // Statement anchors are their first evaluated expression, not the declaration
   85 // name/type or punctuation. They have separate identities from that expression.
   86 pure inventory_block(block: Block, id: Str): [InventoryItem] {
   87   mut items: [InventoryItem] = []
   88   mut index: Nat = 0
   89   for statement in block.statements {
   90     key: Str = id + "/statement/${index}"
   91     match statement {
   92       BindingStatement(name, annotation, mutable, value) => {
   93         items = concat(items, inventory_item(key, "statement", "binding", value))
   94         items = concat(items, inventory_expression(value, key + "/value"))
   95       },
   96       AssignmentStatement(name, value) => {
   97         items = concat(items, inventory_item(key, "statement", "assignment-or-inferred-binding", value))
   98         items = concat(items, inventory_expression(value, key + "/value"))
   99       },
  100       ExpressionStatement(value) => {
  101         items = concat(items, inventory_item(key, "statement", "expression", value))
  102         items = concat(items, inventory_expression(value, key + "/value"))
  103       },
  104       WhileStatement(condition, body) => {
  105         items = concat(items, inventory_item(key, "statement", "while", condition))
  106         items = concat(items, inventory_decision(key + "/decision", "while", condition, ["body", "exit"]))
  107         items = concat(items, inventory_expression(condition, key + "/condition"))
  108         items = concat(items, inventory_block(body, key + "/body"))
  109       },
  110       ForStatement(name, values, body) => {
  111         items = concat(items, inventory_item(key, "statement", "for", values))
  112         items = concat(items, inventory_decision(key + "/decision", "for", values, ["body", "exit"]))
  113         items = concat(items, inventory_expression(values, key + "/iterable"))
  114         items = concat(items, inventory_block(body, key + "/body"))
  115       }
  116     }
  117     index = index + 1
  118   }
  119   match block.value {
  120     NoBlockValue() => {},
  121     TailBlockValue(value) => { items = concat(items, inventory_expression(value, id + "/tail")); }
  122   }
  123   items
  124 }
  125 
  126 pure inventory_module(module: LoadedModule): [InventoryItem] {
  127   mut items: [InventoryItem] = []
  128   mut index: Nat = 0
  129   for declaration in module.parsed.program.declarations {
  130     id: Str = "declaration/${index}"
  131     span: SourceSpan = module.parsed.syntax[index].span
  132     match declaration {
  133       FunctionDeclaration(name, parameters, result, pure_effect, async_effect, body, types) => {
  134         items = items.append(InventoryItem(id, "function", name, span))
  135         items = concat(items, inventory_block(body, id))
  136       },
  137       ImportDeclaration(path) => { items = items.append(InventoryItem(id, "excluded", "import", span)); },
  138       TypeDeclaration(name, base, guard) => { items = items.append(InventoryItem(id, "excluded", "compile-time-refinement", span)); },
  139       RecordDeclaration(name, types, fields) => { items = items.append(InventoryItem(id, "excluded", "record-declaration", span)); },
  140       EnumDeclaration(name, types, variants) => { items = items.append(InventoryItem(id, "excluded", "enum-declaration", span)); }
  141     }
  142     index = index + 1
  143   }
  144   items
  145 }
  146 
  147 // Foreign inventories are never decoded. The caller reproduces this envelope
  148 // using explicit local roots and the installed compiler, then compares bytes.
  149 pure serialize_source_inventory(project: LoadedProject, artifact: Bytes, compiler: Bytes, entry: Str, root: Str, stdlib: Str): Bytes {
  150   snapshots: [SourceSnapshot] = source_snapshots(project, root, stdlib)
  151   mut chunks: [Bytes] = [utf8_encode("PANACKINV1\nlocal-replay-v9\n"), source_map_blob(compiler),
  152     encode_text(source_identifier(entry, root, stdlib)), source_map_blob(artifact), encode_u32(len(snapshots))]
  153   mut size: Nat = 0
  154   mut valid: Bool = byte_len(compiler) > 0 && byte_len(compiler) <= 16777216 &&
  155     byte_len(artifact) <= 16777216 && len(snapshots) <= 256
  156   for chunk in chunks { size = size + byte_len(chunk); }
  157   for snapshot in snapshots {
  158     mut items: [InventoryItem] = []
  159     for module in project.modules {
  160       if module.source_path == snapshot.path { items = inventory_module(module); }
  161     }
  162     chunks = chunks.append(encode_text(snapshot.name)).append(encode_text(snapshot.text)).append(encode_u32(len(items)))
  163     size = size + 12 + byte_len(utf8_encode(snapshot.name)) + byte_len(utf8_encode(snapshot.text))
  164     valid = valid && len(items) <= 100000
  165     for item in items {
  166       if valid && size <= 16777216 {
  167         chunk: Bytes = source_map_join([encode_text(item.id), encode_text(item.kind), encode_text(item.detail),
  168           source_map_position(item.span.start), source_map_position(item.span.end)], 0, 5)
  169         chunks = chunks.append(chunk)
  170         size = size + byte_len(chunk)
  171       } else { valid = false }
  172     }
  173   }
  174   if valid && size <= 16777216 { source_map_join(chunks, 0, len(chunks)) } else { bytes() }
  175 }
  176 
  177 record InventoryArguments {
  178   valid: Bool,
  179   roots: [Str],
  180   output: Str
  181 }
  182 
  183 pure inventory_arguments(values: [Str], checking: Bool): InventoryArguments {
  184   mut roots: [Str] = []
  185   mut output: Str = ""
  186   mut valid: Bool = len(values) >= 4
  187   if valid { roots = roots.append(values[1]); }
  188   mut index: Nat = 2
  189   while index + 1 < len(values) {
  190     flag: Str = values[index]
  191     value: Str = values[index + 1]
  192     if flag == (if checking { "--inventory" } else { "-o" }) && output == "" {
  193       output = value
  194     } else {
  195       if flag == "--include" { roots = roots.append(value); } else { valid = false; }
  196     }
  197     index = index + 2
  198   }
  199   for root in roots { valid = valid && path_suffix(root) == ".panack"; }
  200   InventoryArguments(valid && index == len(values) && output != "" && len(roots) <= 16, roots, output)
  201 }
  202 
  203 // Repeating roots deliberately creates distinct compilation contexts. Shared
  204 // source identities must be deduplicated by a future suite aggregator, never by
  205 // adding these counts. Sources are rechecked after *all* roots have been loaded.
  206 run_inventory_command(values: [Str], checking: Bool): Nat {
  207   args: InventoryArguments = inventory_arguments(values, checking)
  208   if !args.valid {
  209     eprint("error: inventory usage: inventory SOURCE.panack -o FILE [--include SOURCE.panack] | inventory-check SOURCE.panack --inventory FILE [--include SOURCE.panack]")
  210     1
  211   } else {
  212     compiler_path: Str = environment_get("PANACKELTY_COMPILER_PATH")
  213     match source_map_read(compiler_path, 16777216) {
  214       Error(error) => { eprint("error: inventory compiler identity unavailable"); 1 },
  215       Ok(compiler) => {
  216         // The running compiler was verified by the VM. This trusted identity
  217         // input is compared exactly, not decoded again in the hosted compiler.
  218         mut valid: Bool = byte_len(compiler) > 0
  219         mut projects: [LoadedProject] = []
  220         mut paths: Set[Str] = set()
  221         mut chunks: [Bytes] = [utf8_encode("PANACKINVENTORY1\n"), encode_u32(len(args.roots))]
  222         mut size: Nat = byte_len(chunks[0]) + 4
  223         root: Str = path_parent(path_resolve(args.roots[0]))
  224         stdlib: Str = path_resolve(environment_get("PANACKELTY_STDLIB_PATH"))
  225         output: Str = path_resolve(args.output)
  226         if !checking && !source_map_destination_available(output) { valid = false; }
  227         for source in args.roots {
  228           entry: Str = path_resolve(source)
  229           if paths.has(entry) { valid = false; }
  230           paths = paths.add(entry)
  231           if valid {
  232             project: LoadedProject = load_project_for_inventory(entry)
  233             projects = projects.append(project)
  234             if len(project.diagnostics) > 0 { valid = false; }
  235             else {
  236               artifact: Bytes = serialize_bytecode(compile_program(project.program))
  237               inventory: Bytes = serialize_source_inventory(project, artifact, compiler, entry, root, stdlib)
  238               size = size + 4 + byte_len(inventory)
  239               valid = byte_len(inventory) > 0 && size <= 16777216
  240               if valid { chunks = chunks.append(source_map_blob(inventory)); }
  241             }
  242           }
  243         }
  244         for project in projects { valid = valid && source_snapshots_unchanged(project); }
  245         valid = valid && source_map_matches(compiler_path, compiler)
  246         if !valid { eprint("error: inventory unavailable: invalid, changed, duplicate or excessive inputs, or existing output"); 1 }
  247         else {
  248           expected: Bytes = source_map_join(chunks, 0, len(chunks))
  249           if checking {
  250             if source_map_matches(output, expected) { print("inventory: valid"); 0 }
  251             else { eprint("error: inventory unavailable: missing, malformed, stale or incompatible inventory"); 1 }
  252           } else {
  253             if source_map_destination_available(output) && source_map_write(output, expected) && source_map_matches(output, expected) {
  254               print("wrote inventory " + args.output)
  255               0
  256             } else { eprint("error: could not write inventory; discard any partial output"); 1 }
  257           }
  258         }
  259       }
  260     }
  261   }
  262 }
  263 

Functions

[
  {
    "id": "declaration/2",
    "name": "inventory_item",
    "line": 12,
    "state": "covered",
    "entries": "1847"
  },
  {
    "id": "declaration/3",
    "name": "inventory_decision",
    "line": 19,
    "state": "covered",
    "entries": "111"
  },
  {
    "id": "declaration/4",
    "name": "inventory_expressions",
    "line": 27,
    "state": "covered",
    "entries": "269"
  },
  {
    "id": "declaration/5",
    "name": "inventory_expression",
    "line": 37,
    "state": "covered",
    "entries": "1212"
  },
  {
    "id": "declaration/6",
    "name": "inventory_block",
    "line": 86,
    "state": "covered",
    "entries": "204"
  },
  {
    "id": "declaration/7",
    "name": "inventory_module",
    "line": 126,
    "state": "covered",
    "entries": "25"
  },
  {
    "id": "declaration/8",
    "name": "serialize_source_inventory",
    "line": 149,
    "state": "covered",
    "entries": "5"
  },
  {
    "id": "declaration/10",
    "name": "inventory_arguments",
    "line": 183,
    "state": "covered",
    "entries": "5"
  },
  {
    "id": "declaration/11",
    "name": "run_inventory_command",
    "line": 206,
    "state": "zero",
    "entries": "0"
  }
]

Source branch outcomes

[
  {
    "id": "declaration/2/tail/arm/0",
    "outcome": "Some",
    "line": 14,
    "state": "covered",
    "hits": "1847"
  },
  {
    "id": "declaration/2/tail/arm/1",
    "outcome": "None",
    "line": 15,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/3/statement/1/decision/body",
    "outcome": "body",
    "line": 21,
    "state": "covered",
    "hits": "222"
  },
  {
    "id": "declaration/3/statement/1/decision/exit",
    "outcome": "exit",
    "line": 21,
    "state": "covered",
    "hits": "111"
  },
  {
    "id": "declaration/4/statement/2/decision/body",
    "outcome": "body",
    "line": 30,
    "state": "covered",
    "hits": "228"
  },
  {
    "id": "declaration/4/statement/2/decision/exit",
    "outcome": "exit",
    "line": 30,
    "state": "covered",
    "hits": "269"
  },
  {
    "id": "declaration/5/statement/1/value/arm/0",
    "outcome": "LocatedExpr",
    "line": 40,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/5/statement/1/value/arm/1",
    "outcome": "NatExpr",
    "line": 41,
    "state": "covered",
    "hits": "165"
  },
  {
    "id": "declaration/5/statement/1/value/arm/2",
    "outcome": "DecimalExpr",
    "line": 41,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/5/statement/1/value/arm/3",
    "outcome": "StringExpr",
    "line": 41,
    "state": "covered",
    "hits": "8"
  },
  {
    "id": "declaration/5/statement/1/value/arm/4",
    "outcome": "BoolExpr",
    "line": 42,
    "state": "covered",
    "hits": "47"
  },
  {
    "id": "declaration/5/statement/1/value/arm/5",
    "outcome": "NameExpr",
    "line": 42,
    "state": "covered",
    "hits": "455"
  },
  {
    "id": "declaration/5/statement/1/value/arm/6",
    "outcome": "FunctionExpr",
    "line": 42,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/5/statement/1/value/arm/7",
    "outcome": "ArrayExpr",
    "line": 43,
    "state": "covered",
    "hits": "29"
  },
  {
    "id": "declaration/5/statement/1/value/arm/8",
    "outcome": "UnaryExpr",
    "line": 44,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/5/statement/1/value/arm/9",
    "outcome": "BinaryExpr",
    "line": 45,
    "state": "covered",
    "hits": "144"
  },
  {
    "id": "declaration/5/statement/1/value/arm/9/body/block/statement/0/value/decision/true",
    "outcome": "true",
    "line": 46,
    "state": "covered",
    "hits": "23"
  },
  {
    "id": "declaration/5/statement/1/value/arm/9/body/block/statement/0/value/decision/false",
    "outcome": "false",
    "line": 46,
    "state": "covered",
    "hits": "121"
  },
  {
    "id": "declaration/5/statement/1/value/arm/9/body/block/statement/0/value/condition/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 46,
    "state": "covered",
    "hits": "129"
  },
  {
    "id": "declaration/5/statement/1/value/arm/9/body/block/statement/0/value/condition/decision/skip-right",
    "outcome": "skip-right",
    "line": 46,
    "state": "covered",
    "hits": "15"
  },
  {
    "id": "declaration/5/statement/1/value/arm/10",
    "outcome": "CallExpr",
    "line": 52,
    "state": "covered",
    "hits": "128"
  },
  {
    "id": "declaration/5/statement/1/value/arm/11",
    "outcome": "DotCallExpr",
    "line": 53,
    "state": "covered",
    "hits": "112"
  },
  {
    "id": "declaration/5/statement/1/value/arm/12",
    "outcome": "FieldExpr",
    "line": 57,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/5/statement/1/value/arm/13",
    "outcome": "IndexExpr",
    "line": 58,
    "state": "covered",
    "hits": "63"
  },
  {
    "id": "declaration/5/statement/1/value/arm/14",
    "outcome": "IfExpr",
    "line": 62,
    "state": "covered",
    "hits": "37"
  },
  {
    "id": "declaration/5/statement/1/value/arm/15",
    "outcome": "BlockExpr",
    "line": 68,
    "state": "covered",
    "hits": "16"
  },
  {
    "id": "declaration/5/statement/1/value/arm/16",
    "outcome": "MatchExpr",
    "line": 69,
    "state": "covered",
    "hits": "8"
  },
  {
    "id": "declaration/5/statement/1/value/arm/16/body/block/statement/3/decision/body",
    "outcome": "body",
    "line": 73,
    "state": "covered",
    "hits": "16"
  },
  {
    "id": "declaration/5/statement/1/value/arm/16/body/block/statement/3/decision/exit",
    "outcome": "exit",
    "line": 73,
    "state": "covered",
    "hits": "8"
  },
  {
    "id": "declaration/6/statement/2/decision/body",
    "outcome": "body",
    "line": 89,
    "state": "covered",
    "hits": "278"
  },
  {
    "id": "declaration/6/statement/2/decision/exit",
    "outcome": "exit",
    "line": 89,
    "state": "covered",
    "hits": "204"
  },
  {
    "id": "declaration/6/statement/2/body/statement/1/value/arm/0",
    "outcome": "BindingStatement",
    "line": 92,
    "state": "covered",
    "hits": "66"
  },
  {
    "id": "declaration/6/statement/2/body/statement/1/value/arm/1",
    "outcome": "AssignmentStatement",
    "line": 96,
    "state": "covered",
    "hits": "120"
  },
  {
    "id": "declaration/6/statement/2/body/statement/1/value/arm/2",
    "outcome": "ExpressionStatement",
    "line": 100,
    "state": "covered",
    "hits": "41"
  },
  {
    "id": "declaration/6/statement/2/body/statement/1/value/arm/3",
    "outcome": "WhileStatement",
    "line": 104,
    "state": "covered",
    "hits": "29"
  },
  {
    "id": "declaration/6/statement/2/body/statement/1/value/arm/4",
    "outcome": "ForStatement",
    "line": 110,
    "state": "covered",
    "hits": "22"
  },
  {
    "id": "declaration/6/statement/3/value/arm/0",
    "outcome": "NoBlockValue",
    "line": 120,
    "state": "covered",
    "hits": "85"
  },
  {
    "id": "declaration/6/statement/3/value/arm/1",
    "outcome": "TailBlockValue",
    "line": 121,
    "state": "covered",
    "hits": "119"
  },
  {
    "id": "declaration/7/statement/2/decision/body",
    "outcome": "body",
    "line": 129,
    "state": "covered",
    "hits": "109"
  },
  {
    "id": "declaration/7/statement/2/decision/exit",
    "outcome": "exit",
    "line": 129,
    "state": "covered",
    "hits": "25"
  },
  {
    "id": "declaration/7/statement/2/body/statement/2/value/arm/0",
    "outcome": "FunctionDeclaration",
    "line": 133,
    "state": "covered",
    "hits": "63"
  },
  {
    "id": "declaration/7/statement/2/body/statement/2/value/arm/1",
    "outcome": "ImportDeclaration",
    "line": 137,
    "state": "covered",
    "hits": "8"
  },
  {
    "id": "declaration/7/statement/2/body/statement/2/value/arm/2",
    "outcome": "TypeDeclaration",
    "line": 138,
    "state": "covered",
    "hits": "8"
  },
  {
    "id": "declaration/7/statement/2/body/statement/2/value/arm/3",
    "outcome": "RecordDeclaration",
    "line": 139,
    "state": "covered",
    "hits": "8"
  },
  {
    "id": "declaration/7/statement/2/body/statement/2/value/arm/4",
    "outcome": "EnumDeclaration",
    "line": 140,
    "state": "covered",
    "hits": "22"
  },
  {
    "id": "declaration/8/statement/3/value/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 154,
    "state": "covered",
    "hits": "4"
  },
  {
    "id": "declaration/8/statement/3/value/decision/skip-right",
    "outcome": "skip-right",
    "line": 154,
    "state": "covered",
    "hits": "1"
  },
  {
    "id": "declaration/8/statement/3/value/left/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 154,
    "state": "covered",
    "hits": "4"
  },
  {
    "id": "declaration/8/statement/3/value/left/decision/skip-right",
    "outcome": "skip-right",
    "line": 154,
    "state": "covered",
    "hits": "1"
  },
  {
    "id": "declaration/8/statement/3/value/left/left/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 154,
    "state": "covered",
    "hits": "4"
  },
  {
    "id": "declaration/8/statement/3/value/left/left/decision/skip-right",
    "outcome": "skip-right",
    "line": 154,
    "state": "covered",
    "hits": "1"
  },
  {
    "id": "declaration/8/statement/4/decision/body",
    "outcome": "body",
    "line": 156,
    "state": "covered",
    "hits": "25"
  },
  {
    "id": "declaration/8/statement/4/decision/exit",
    "outcome": "exit",
    "line": 156,
    "state": "covered",
    "hits": "5"
  },
  {
    "id": "declaration/8/statement/5/decision/body",
    "outcome": "body",
    "line": 157,
    "state": "covered",
    "hits": "15"
  },
  {
    "id": "declaration/8/statement/5/decision/exit",
    "outcome": "exit",
    "line": 157,
    "state": "covered",
    "hits": "5"
  },
  {
    "id": "declaration/8/statement/5/body/statement/1/decision/body",
    "outcome": "body",
    "line": 159,
    "state": "covered",
    "hits": "45"
  },
  {
    "id": "declaration/8/statement/5/body/statement/1/decision/exit",
    "outcome": "exit",
    "line": 159,
    "state": "covered",
    "hits": "15"
  },
  {
    "id": "declaration/8/statement/5/body/statement/1/body/tail/decision/true",
    "outcome": "true",
    "line": 160,
    "state": "covered",
    "hits": "15"
  },
  {
    "id": "declaration/8/statement/5/body/statement/1/body/tail/decision/false",
    "outcome": "false",
    "line": 160,
    "state": "covered",
    "hits": "30"
  },
  {
    "id": "declaration/8/statement/5/body/statement/4/value/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 164,
    "state": "covered",
    "hits": "12"
  },
  {
    "id": "declaration/8/statement/5/body/statement/4/value/decision/skip-right",
    "outcome": "skip-right",
    "line": 164,
    "state": "covered",
    "hits": "3"
  },
  {
    "id": "declaration/8/statement/5/body/statement/5/decision/body",
    "outcome": "body",
    "line": 165,
    "state": "covered",
    "hits": "1335"
  },
  {
    "id": "declaration/8/statement/5/body/statement/5/decision/exit",
    "outcome": "exit",
    "line": 165,
    "state": "covered",
    "hits": "15"
  },
  {
    "id": "declaration/8/statement/5/body/statement/5/body/tail/decision/true",
    "outcome": "true",
    "line": 166,
    "state": "covered",
    "hits": "1068"
  },
  {
    "id": "declaration/8/statement/5/body/statement/5/body/tail/decision/false",
    "outcome": "false",
    "line": 166,
    "state": "covered",
    "hits": "267"
  },
  {
    "id": "declaration/8/statement/5/body/statement/5/body/tail/condition/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 166,
    "state": "covered",
    "hits": "1068"
  },
  {
    "id": "declaration/8/statement/5/body/statement/5/body/tail/condition/decision/skip-right",
    "outcome": "skip-right",
    "line": 166,
    "state": "covered",
    "hits": "267"
  },
  {
    "id": "declaration/8/tail/decision/true",
    "outcome": "true",
    "line": 174,
    "state": "covered",
    "hits": "4"
  },
  {
    "id": "declaration/8/tail/decision/false",
    "outcome": "false",
    "line": 174,
    "state": "covered",
    "hits": "1"
  },
  {
    "id": "declaration/8/tail/condition/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 174,
    "state": "covered",
    "hits": "4"
  },
  {
    "id": "declaration/8/tail/condition/decision/skip-right",
    "outcome": "skip-right",
    "line": 174,
    "state": "covered",
    "hits": "1"
  },
  {
    "id": "declaration/10/statement/3/value/decision/true",
    "outcome": "true",
    "line": 187,
    "state": "covered",
    "hits": "4"
  },
  {
    "id": "declaration/10/statement/3/value/decision/false",
    "outcome": "false",
    "line": 187,
    "state": "covered",
    "hits": "1"
  },
  {
    "id": "declaration/10/statement/5/decision/body",
    "outcome": "body",
    "line": 189,
    "state": "covered",
    "hits": "5"
  },
  {
    "id": "declaration/10/statement/5/decision/exit",
    "outcome": "exit",
    "line": 189,
    "state": "covered",
    "hits": "5"
  },
  {
    "id": "declaration/10/statement/5/body/statement/2/value/decision/true",
    "outcome": "true",
    "line": 192,
    "state": "covered",
    "hits": "3"
  },
  {
    "id": "declaration/10/statement/5/body/statement/2/value/decision/false",
    "outcome": "false",
    "line": 192,
    "state": "covered",
    "hits": "2"
  },
  {
    "id": "declaration/10/statement/5/body/statement/2/value/condition/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 192,
    "state": "covered",
    "hits": "4"
  },
  {
    "id": "declaration/10/statement/5/body/statement/2/value/condition/decision/skip-right",
    "outcome": "skip-right",
    "line": 192,
    "state": "covered",
    "hits": "1"
  },
  {
    "id": "declaration/10/statement/5/body/statement/2/value/condition/left/right/decision/true",
    "outcome": "true",
    "line": 192,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/10/statement/5/body/statement/2/value/condition/left/right/decision/false",
    "outcome": "false",
    "line": 192,
    "state": "covered",
    "hits": "5"
  },
  {
    "id": "declaration/10/statement/5/body/statement/2/value/false/tail/decision/true",
    "outcome": "true",
    "line": 195,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/10/statement/5/body/statement/2/value/false/tail/decision/false",
    "outcome": "false",
    "line": 195,
    "state": "covered",
    "hits": "2"
  },
  {
    "id": "declaration/10/statement/6/decision/body",
    "outcome": "body",
    "line": 199,
    "state": "covered",
    "hits": "4"
  },
  {
    "id": "declaration/10/statement/6/decision/exit",
    "outcome": "exit",
    "line": 199,
    "state": "covered",
    "hits": "5"
  },
  {
    "id": "declaration/10/statement/6/body/statement/0/value/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 199,
    "state": "covered",
    "hits": "2"
  },
  {
    "id": "declaration/10/statement/6/body/statement/0/value/decision/skip-right",
    "outcome": "skip-right",
    "line": 199,
    "state": "covered",
    "hits": "2"
  },
  {
    "id": "declaration/10/tail/args/0/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 200,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/10/tail/args/0/decision/skip-right",
    "outcome": "skip-right",
    "line": 200,
    "state": "covered",
    "hits": "5"
  },
  {
    "id": "declaration/10/tail/args/0/left/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 200,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/10/tail/args/0/left/decision/skip-right",
    "outcome": "skip-right",
    "line": 200,
    "state": "covered",
    "hits": "5"
  },
  {
    "id": "declaration/10/tail/args/0/left/left/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 200,
    "state": "covered",
    "hits": "1"
  },
  {
    "id": "declaration/10/tail/args/0/left/left/decision/skip-right",
    "outcome": "skip-right",
    "line": 200,
    "state": "covered",
    "hits": "4"
  },
  {
    "id": "declaration/11/tail/decision/true",
    "outcome": "true",
    "line": 208,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/decision/false",
    "outcome": "false",
    "line": 208,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/0",
    "outcome": "Error",
    "line": 214,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1",
    "outcome": "Ok",
    "line": 215,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/8/value/decision/true",
    "outcome": "true",
    "line": 226,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/8/value/decision/false",
    "outcome": "false",
    "line": 226,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/8/value/condition/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 226,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/8/value/condition/decision/skip-right",
    "outcome": "skip-right",
    "line": 226,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/9/decision/body",
    "outcome": "body",
    "line": 227,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/9/decision/exit",
    "outcome": "exit",
    "line": 227,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/9/body/statement/1/value/decision/true",
    "outcome": "true",
    "line": 229,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/9/body/statement/1/value/decision/false",
    "outcome": "false",
    "line": 229,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/9/body/tail/decision/true",
    "outcome": "true",
    "line": 231,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/9/body/tail/decision/false",
    "outcome": "false",
    "line": 231,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/9/body/tail/true/tail/decision/true",
    "outcome": "true",
    "line": 234,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/9/body/tail/true/tail/decision/false",
    "outcome": "false",
    "line": 234,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/9/body/tail/true/tail/false/statement/3/value/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 239,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/9/body/tail/true/tail/false/statement/3/value/decision/skip-right",
    "outcome": "skip-right",
    "line": 239,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/9/body/tail/true/tail/false/tail/decision/true",
    "outcome": "true",
    "line": 240,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/9/body/tail/true/tail/false/tail/decision/false",
    "outcome": "false",
    "line": 240,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/10/decision/body",
    "outcome": "body",
    "line": 244,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/10/decision/exit",
    "outcome": "exit",
    "line": 244,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/10/body/statement/0/value/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 244,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/10/body/statement/0/value/decision/skip-right",
    "outcome": "skip-right",
    "line": 244,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/11/value/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 245,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/statement/11/value/decision/skip-right",
    "outcome": "skip-right",
    "line": 245,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/tail/decision/true",
    "outcome": "true",
    "line": 246,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/tail/decision/false",
    "outcome": "false",
    "line": 246,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/tail/false/tail/decision/true",
    "outcome": "true",
    "line": 249,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/tail/false/tail/decision/false",
    "outcome": "false",
    "line": 249,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/tail/false/tail/true/tail/decision/true",
    "outcome": "true",
    "line": 250,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/tail/false/tail/true/tail/decision/false",
    "outcome": "false",
    "line": 250,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/tail/false/tail/false/tail/decision/true",
    "outcome": "true",
    "line": 253,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/tail/false/tail/false/tail/decision/false",
    "outcome": "false",
    "line": 253,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/tail/false/tail/false/tail/condition/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 253,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/tail/false/tail/false/tail/condition/decision/skip-right",
    "outcome": "skip-right",
    "line": 253,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/tail/false/tail/false/tail/condition/left/decision/evaluate-right",
    "outcome": "evaluate-right",
    "line": 253,
    "state": "zero",
    "hits": "0"
  },
  {
    "id": "declaration/11/tail/false/tail/arm/1/body/block/tail/false/tail/false/tail/condition/left/decision/skip-right",
    "outcome": "skip-right",
    "line": 253,
    "state": "zero",
    "hits": "0"
  }
]

Reviewed declaration exclusions

[
  {
    "id": "declaration/0",
    "reason": "import",
    "line": 1
  },
  {
    "id": "declaration/1",
    "reason": "record-declaration",
    "line": 5
  },
  {
    "id": "declaration/9",
    "reason": "record-declaration",
    "line": 177
  }
]