@@ -66,11 +66,12 @@ Only these top-level keys are accepted:
6666- ` patterns ` (optional for structural rules): non-empty YAML array
6767- ` patterns-not ` (optional for structural rules): non-empty YAML array using
6868 the same object schema as ` patterns `
69- - ` inside-expr ` (optional for structural rules): YAML mapping using the same
70- ` shape ` and optional ` guard ` schema as ` patterns ` , used as an outer context
71- - ` inside-toplevel ` (optional for structural rules): YAML mapping using the
72- same ` shape ` and optional ` guard ` schema as ` inside-expr ` ; its shape is parsed
73- as one MoonBit top-level item
69+ - ` inside-expr ` (optional for structural rules): non-empty YAML array using the
70+ same ` shape ` and optional ` guard ` object schema as ` patterns ` ; entries are
71+ ordered alternative outer expression contexts
72+ - ` inside-toplevel ` (optional for structural rules): non-empty YAML array using
73+ the same object schema as ` inside-expr ` ; each shape is parsed as one MoonBit
74+ top-level item
7475- ` taint ` (required for taint rules): YAML mapping
7576
7677Unknown top-level keys are rejected.
@@ -109,18 +110,18 @@ is invalid in these entries.
109110
110111## Shapes
111112
112- An ordinary ` shape ` must be a single MoonBit expression snippet.
113- ` inside-toplevel. shape ` must be exactly one MoonBit top-level item.
113+ An ordinary ` shape ` must be a single MoonBit expression snippet. Each
114+ ` inside-toplevel ` entry's ` shape ` must be exactly one MoonBit top-level item.
114115
115116Valid expression shapes include calls, method calls, field accesses,
116117operators, blocks, conditionals, loops, matches, lambdas, collection literals,
117118record expressions, and other expression-sized MoonBit syntax. Ordinary
118119` patterns ` , ` patterns-not ` , and ` inside-expr ` shapes are not a whole file,
119120top-level declaration, package fragment, or import list.
120121
121- ` inside-toplevel.shape ` is parsed as one top-level item, such as a function,
122- top-level ` let ` , ` test ` , method ` impl ` , view, or top-level expression. It is
123- one item and cannot represent a whole file or import list.
122+ Each ` inside-toplevel ` shape is parsed as one top-level item, such as a
123+ function, top-level ` let ` , ` test ` , method ` impl ` , view, or top-level expression.
124+ It is one item and cannot represent a whole file or import list.
124125
125126Shapes are structural:
126127
@@ -714,47 +715,56 @@ context. It may be used with `patterns`, with `patterns-not`, or with both.
714715` ` ` yaml
715716id: wrapped-target
716717description: |
717- Match a target call only inside wrapper(...) .
718+ Match a target call inside either supported context .
718719inside-expr:
719- shape: wrapper($(prefix:exp), __TARGET__)
720+ - shape: wrapper($(prefix:exp), __TARGET__)
721+ - shape: container($(prefix:exp), __TARGET__)
720722patterns:
721723 - shape: target.call($(prefix:exp))
722724` ` `
723725
724- ` inside-expr` is a YAML mapping. Its `shape` is parsed as one MoonBit
725- expression snippet, and its optional `guard` filters `id` and `const` captures
726- declared by that outer shape.
726+ ` inside-expr` is a non-empty YAML array of pattern objects. Each `shape` is
727+ parsed as one MoonBit expression snippet, and its optional `guard` filters `id`
728+ and `const` captures declared by that outer shape. Entries are ordered
729+ alternatives.
727730
728731Additional rules :
729732
730- - ` inside-expr` must contain exactly one `__TARGET__` occurrence in a
731- binding-capable position.
733+ - Every `inside-expr` entry must contain exactly one `__TARGET__` occurrence in
734+ a binding-capable position.
732735- ` __TARGET__` must occupy a whole expression position, such as a whole call
733736 argument, receiver, or block expression. If it appears only as a label or
734737 other non-expression value, no target subtree can be searched.
735738- ` __TARGET__` is reserved and must not be used as an metavar name.
736739- Entries in `patterns` and `patterns-not` must not contain `__TARGET__` in a
737740 binding-capable position.
738- - Metavars declared by `inside-expr` remain visible when matching the
739- inner pattern entries; inner shapes reference them by repeating the same
740- metavar form.
741- - Inner `patterns` and `patterns-not` must not use a visible `inside-expr`
742- metavar name with a different kind.
741+ - Captures declared by the selected `inside-expr` entry remain visible when
742+ matching the inner pattern entries; inner shapes reference them by repeating
743+ the same metavar form.
744+ - Any capture reused by an inner `patterns` or `patterns-not` entry must be
745+ declared by every `inside-expr` alternative with the same kind. This includes
746+ named ellipsis captures and their ellipsis kinds. Outer captures that are not
747+ referenced by an inner entry may differ between alternatives.
743748
744749Runtime behavior :
745750
746- - the current expression is first matched against `inside-expr`
747- - if it matches, the subtree captured by `__TARGET__` is searched
751+ - the current expression tries eligible `inside-expr` entries in YAML order
752+ - an entry whose shape does not match, or whose guard fails, falls through to
753+ the next entry
754+ - the first entry whose shape and guard both match selects the captured
755+ ` __TARGET__` subtree and bindings
756+ - once an entry is selected, later alternatives are not tried even if inner
757+ matching produces no finding
748758- when `patterns` is present, each expression in the captured subtree first
749759 tries the ordered positive patterns using the bindings established by
750- ` inside-expr ` ; a positive hit is recorded and its matched subtree covers any
751- nested negative matches
760+ the selected outer entry ; a positive hit is recorded and its matched subtree
761+ covers any nested negative matches
752762- when `patterns` and `patterns-not` are both present, a candidate that fails
753763 all positive patterns is then checked against `patterns-not` using the
754- ` inside-expr ` bindings; a negative match outside a positive-hit subtree
764+ the selected outer bindings; a negative match outside a positive-hit subtree
755765 rejects the whole outer match
756766- when `patterns` is absent, every expression in the captured subtree is
757- checked against `patterns-not` using the `inside-expr` bindings; if none of
767+ checked against `patterns-not` using the selected outer bindings; if none of
758768 them match, the outer expression produces one hit
759769- if an inner positive or negative pattern references an inherited `id` capture
760770 with the same inline `$(name:id)` form, that candidate is skipped when the
@@ -769,39 +779,42 @@ outer expression do not produce additional findings. With only `patterns-not`,
769779
770780# ## `inside-toplevel`
771781
772- ` inside-toplevel` restricts a structural rule to matches inside one MoonBit
773- top-level item . It uses the same object schema and target-subtree semantics as
774- ` inside-expr` . Its `shape` is parsed as exactly one top-level item, not as an
775- expression.
782+ ` inside-toplevel` restricts a structural rule to matches inside selected
783+ MoonBit top-level items . It is a non-empty ordered array using the same object
784+ schema and target-subtree semantics as `inside-expr`. Each entry's `shape` is
785+ parsed as exactly one top-level item, not as an expression.
776786
777787` ` ` yaml
778788id: safe-function-target
779789description: |
780790 Match calls only in selected top-level functions.
781791inside-toplevel:
782- shape: |
783- fn $(name:id)($(param:id) : Int) -> Int { __TARGET__ }
784- guard:
785- $name: "^safe_"
792+ - shape: |
793+ fn $(name:id)($(param:id) : Int) -> Int { __TARGET__ }
794+ guard:
795+ $name: "^safe_"
786796patterns:
787797 - shape: call($(param:id))
788798` ` `
789799
790800Additional rules :
791801
792802- ` inside-toplevel` and `inside-expr` are mutually exclusive.
793- - ` inside-toplevel` must contain exactly one `__TARGET__` occurrence in a
794- binding-capable expression position within the top-level item.
803+ - Every `inside-toplevel` entry must contain exactly one `__TARGET__`
804+ occurrence in a binding-capable expression position within the top-level
805+ item.
795806- The top-level item itself may declare `id` and `const` captures, and its
796807 optional `guard` may filter those captures.
797- - Metavars declared by `inside-toplevel` remain visible to inner `patterns` and
798- ` patterns-not` , using the same inherited binding and kind-consistency rules as
799- ` inside-expr` .
808+ - Captures declared by the selected `inside-toplevel` entry remain visible to
809+ inner `patterns` and `patterns -not`, using the same all-alternatives
810+ declaration and kind-consistency rules as `inside-expr`.
800811- ` inside-toplevel` is not supported on taint rules.
801812
802- The candidate top-level item is first matched against `inside-toplevel`; if it
803- matches, the expression subtree captured by `__TARGET__` is searched with the
804- same inherited-binding and negative-coverage behavior as `inside-expr`.
813+ The candidate top-level item tries eligible `inside-toplevel` entries in YAML
814+ order. The first entry whose shape and guard both match selects the target and
815+ bindings; later alternatives are not tried after selection. The expression
816+ subtree captured by `__TARGET__` is searched with the same inherited-binding
817+ and negative-coverage behavior as `inside-expr`.
805818Reporting differs : with `patterns`, every inner positive hit produces a
806819finding whose `loc` is the inner match location. With only `patterns-not`, one
807820finding is produced at the matched top-level item location.
@@ -933,8 +946,8 @@ A rule set or rule file is rejected when any of these conditions occurs:
933946- ` inside-expr` appears on a taint rule
934947- ` inside-toplevel` appears on a taint rule
935948- both `inside-expr` and `inside-toplevel` appear
936- - ` inside-expr` has a non-mapping value
937- - ` inside-toplevel` has a non- mapping value
949+ - ` inside-expr` or `inside-toplevel` is not an array or is empty
950+ - an `inside-expr` or `inside- toplevel` entry is not a mapping
938951- ` inside-expr` is present without `patterns` or `patterns-not`
939952- ` inside-toplevel` is present without `patterns` or `patterns-not`
940953- ` patterns` is not an array or is empty
@@ -953,7 +966,8 @@ A rule set or rule file is rejected when any of these conditions occurs:
953966- ` guard` appears in any taint clause
954967- ` metavars` appears in any pattern object
955968- ` shape` is not valid as one MoonBit expression
956- - ` inside-toplevel.shape` is not exactly one valid MoonBit top-level item
969+ - an `inside-toplevel` entry's `shape` is not exactly one valid MoonBit
970+ top-level item
957971- a shape uses an unsupported metavar kind
958972- a shape uses the same metavar name across multiple metavar kinds
959973- a bare `$name` cannot be inferred to one compatible kind
@@ -970,12 +984,16 @@ A rule set or rule file is rejected when any of these conditions occurs:
970984- an ellipsis kind is incompatible with its list position, conflicts with
971985 another typed occurrence, or shares a name with a normal metavar
972986- a guard regex is invalid
973- - ` inside-expr` does not contain exactly one binding-capable `__TARGET__`
974- - ` inside-toplevel` does not contain exactly one binding-capable `__TARGET__`
987+ - an `inside-expr` entry does not contain exactly one binding-capable
988+ ` __TARGET__`
989+ - an `inside-toplevel` entry does not contain exactly one binding-capable
990+ ` __TARGET__`
975991- a structural `patterns` or `patterns-not` entry contains binding-capable
976992 ` __TARGET__`
977993- a structural `patterns` or `patterns-not` entry uses an inherited
978994 ` inside-expr` or `inside-toplevel` metavar name with a different kind
995+ - a capture reused by `patterns` or `patterns-not` is missing from any outer
996+ alternative, or a named ellipsis is declared with a different ellipsis kind
979997- a taint source contains binding-capable `__SOURCE__`
980998- a taint sink or sanitizer does not contain exactly one binding-capable
981999 ` __SOURCE__`
@@ -1022,7 +1040,7 @@ id: unsafe-wrapper
10221040description: |
10231041 Match a sink only under an unsafe wrapper.
10241042inside-expr:
1025- shape: unsafe(__TARGET__)
1043+ - shape: unsafe(__TARGET__)
10261044patterns:
10271045 - shape: sink($_)
10281046` ` `
@@ -1056,7 +1074,7 @@ id: wrapper-without-danger
10561074description: |
10571075 Match wrappers whose payload contains no danger call.
10581076inside-expr:
1059- shape: wrapper(__TARGET__)
1077+ - shape: wrapper(__TARGET__)
10601078patterns-not:
10611079 - shape: danger()
10621080` ` `
0 commit comments