///|
/// SFC compiler entrypoint and code generators.
///|
pub fn compile(
source : String,
filename? : String = "Component.mbtv",
) -> CompileOutput raise CompilerError {
let doc = @sfc.parse_sfc(source, filename~)
let template = @template.parse_template(doc.template)
compile_from_parts(doc, template, filename)
}
///|
/// Assemble CompileOutput from pre-parsed SFC document and template nodes.
/// Use this when you already have parsed results (e.g. from incremental queries).
pub fn compile_from_parts(
doc : SfcDocument,
template : Array[TemplateNode],
filename : String,
) -> CompileOutput raise CompilerError {
reject_legacy_emit_calls(doc, template, filename)
let resolved_template_refs = resolve_template_refs(
doc.template_refs,
template,
)
let resolved_doc = resolve_template_ref_doc(doc, resolved_template_refs)
let bound_template = bind_template_ref_nodes(template, resolved_template_refs)
let component_name = @codegen.pascal_case(@codegen.base_name(filename))
let scope_id = compute_scope_id(resolved_doc, filename)
let css_output = @codegen.emit_css(resolved_doc.styles, scope_id)
{
filename,
component_name,
extension: resolved_doc.extension,
client_code: @codegen.emit_client_module(
resolved_doc, bound_template, component_name, scope_id,
),
server_code: @codegen.emit_server_module(
resolved_doc, bound_template, component_name, scope_id,
),
css_output,
scope_id,
island_components: @codegen.collect_island_components(bound_template),
generics: resolved_doc.generics,
props_binding: resolved_doc.props_binding,
props: resolved_doc.props,
emits_binding: resolved_doc.emits_binding,
emits: resolved_doc.emits,
slots_binding: resolved_doc.slots_binding,
slots: resolved_doc.slots,
}
}
///|
priv struct ResolvedTemplateRef {
binding_name : String?
arg_source : String
ref_name : String?
type_name : String
}
///|
pub fn compute_scope_id(doc : SfcDocument, filename : String) -> String? {
if doc.has_scoped_style() {
Some("vm-" + @codegen.hash_string(filename))
} else {
None
}
}
///|
fn reject_legacy_emit_calls(
doc : SfcDocument,
nodes : Array[TemplateNode],
filename : String,
) -> Unit raise CompilerError {
validate_template_expressions(nodes, doc.emits_binding, filename)
match doc.emits_binding {
Some(binding) =>
match doc.script_setup {
Some(script) if script_setup_contains_legacy_emit_call(
script, binding, filename,
) =>
raise CompilerError::InvalidScriptSetup(
legacy_emit_message(binding, filename),
)
_ => ()
}
None => ()
}
}
///|
fn validate_template_expressions(
nodes : Array[TemplateNode],
binding : String?,
filename : String,
) -> Unit raise CompilerError {
for node in nodes {
validate_template_node(node, binding, filename)
}
}
///|
fn validate_template_node(
node : TemplateNode,
binding : String?,
filename : String,
) -> Unit raise CompilerError {
match node {
Text(_) => ()
Interpolation(expr) => validate_template_expr(expr, binding, filename)
Element(element) => {
match element.if_expr {
Some(expr) => validate_template_expr(expr, binding, filename)
None => ()
}
match element.for_binding {
Some(binding_) =>
validate_template_expr(binding_.source, binding, filename)
None => ()
}
match element.show_expr {
Some(expr) => validate_template_expr(expr, binding, filename)
None => ()
}
match element.html_expr {
Some(expr) => validate_template_expr(expr, binding, filename)
None => ()
}
match element.model {
Some(model) => {
let parsed = validate_template_expr_with_ast(
model.expression,
binding,
filename,
)
validate_model_target_expr(parsed, model.expression, element.tag)
}
None => ()
}
match element.key_expr {
Some(expr) => validate_template_expr(expr, binding, filename)
None => ()
}
match element.ref_name {
Some(expr) => validate_template_expr(expr, binding, filename)
None => ()
}
for attr in element.attrs {
match attr.kind {
Dynamic | Event =>
validate_template_expr(attr.value, binding, filename)
Static | Boolean => ()
}
}
for child in element.children {
validate_template_node(child, binding, filename)
}
}
Conditional(branches) =>
for branch in branches {
match branch.condition {
Some(expr) => validate_template_expr(expr, binding, filename)
None => ()
}
validate_template_node(Element(branch.element), binding, filename)
}
Match(node) =>
for branch in node.branches {
validate_template_node(Element(branch.element), binding, filename)
}
}
}
///|
fn resolve_template_refs(
template_refs : Array[ScriptSetupTemplateRef],
nodes : Array[TemplateNode],
) -> Array[ResolvedTemplateRef] {
let static_ref_types = collect_static_template_ref_types(nodes)
let resolved : Array[ResolvedTemplateRef] = []
for template_ref in template_refs {
let type_name = match template_ref.ref_name {
Some(name) =>
find_static_template_ref_type(static_ref_types, name).unwrap_or(
"@js_dom.Element",
)
None => "@js_dom.Element"
}
resolved.push({
binding_name: template_ref.binding_name,
arg_source: template_ref.arg_source,
ref_name: template_ref.ref_name,
type_name,
})
}
resolved
}
///|
fn collect_static_template_ref_types(
nodes : Array[TemplateNode],
) -> Array[(String, String)] {
let refs : Array[(String, String)] = []
for node in nodes {
collect_static_template_ref_types_into(node, refs)
}
refs
}
///|
fn collect_static_template_ref_types_into(
node : TemplateNode,
refs : Array[(String, String)],
) -> Unit {
match node {
Text(_) | Interpolation(_) => ()
Element(element) => {
match element.ref_static_name {
Some(name) =>
register_static_template_ref_type(
refs,
name,
infer_template_ref_type(element),
)
None => ()
}
for child in element.children {
collect_static_template_ref_types_into(child, refs)
}
}
Conditional(branches) =>
for branch in branches {
collect_static_template_ref_types_into(Element(branch.element), refs)
}
Match(node) =>
for branch in node.branches {
collect_static_template_ref_types_into(Element(branch.element), refs)
}
}
}
///|
fn register_static_template_ref_type(
refs : Array[(String, String)],
name : String,
next_type : String,
) -> Unit {
for i in 0.. String {
if element.is_component {
return "@js_dom.HTMLElement"
}
infer_native_template_ref_type(element.tag)
}
///|
fn infer_native_template_ref_type(tag : String) -> String {
match tag {
"a" => "@js_dom.HTMLAnchorElement"
"body" => "@js_dom.HTMLBodyElement"
"button" => "@js_dom.HTMLButtonElement"
"canvas" => "@js_dom.HTMLCanvasElement"
"div" => "@js_dom.HTMLDivElement"
"form" => "@js_dom.HTMLFormElement"
"h1" | "h2" | "h3" | "h4" | "h5" | "h6" => "@js_dom.HTMLHeadingElement"
"head" => "@js_dom.HTMLHeadElement"
"html" => "@js_dom.HTMLHtmlElement"
"iframe" => "@js_dom.HTMLIFrameElement"
"img" => "@js_dom.HTMLImageElement"
"input" => "@js_dom.HTMLInputElement"
"label" => "@js_dom.HTMLLabelElement"
"li" => "@js_dom.HTMLLIElement"
"ol" => "@js_dom.HTMLOListElement"
"option" => "@js_dom.HTMLOptionElement"
"p" => "@js_dom.HTMLParagraphElement"
"select" => "@js_dom.HTMLSelectElement"
"span" => "@js_dom.HTMLSpanElement"
"textarea" => "@js_dom.HTMLTextAreaElement"
"ul" => "@js_dom.HTMLUListElement"
_ => "@js_dom.HTMLElement"
}
}
///|
fn merge_template_ref_type(current : String, next_ : String) -> String {
if current == next_ {
return current
}
if current == "@js_dom.Element" || next_ == "@js_dom.Element" {
return "@js_dom.Element"
}
"@js_dom.HTMLElement"
}
///|
fn find_static_template_ref_type(
refs : Array[(String, String)],
name : String,
) -> String? {
for ref_ in refs {
if ref_.0 == name {
return Some(ref_.1)
}
}
None
}
///|
fn resolve_template_ref_doc(
doc : SfcDocument,
resolved_refs : Array[ResolvedTemplateRef],
) -> SfcDocument {
if resolved_refs.is_empty() {
return doc
}
let transformed = match doc.script_setup_transformed {
Some(script_setup) =>
Some(specialize_template_ref_calls(script_setup, resolved_refs))
None => None
}
let imports = append_unique_import(
doc.script_setup_import_entries,
"\"mizchi/js/browser/dom\" @js_dom,",
)
{
..doc,
script_setup_transformed: transformed,
script_setup_import_entries: imports,
}
}
///|
fn specialize_template_ref_calls(
script_setup : String,
resolved_refs : Array[ResolvedTemplateRef],
) -> String {
let mut current = script_setup
for ref_ in resolved_refs {
match ref_.binding_name {
Some(binding_name) =>
current = current.replace_all(
old="let " +
binding_name +
" = @hlp.use_template_ref(" +
ref_.arg_source +
")",
new="let " +
binding_name +
" : @hlp.TemplateRef[" +
ref_.type_name +
"] = @hlp.use_template_ref(" +
ref_.arg_source +
")",
)
None => ()
}
}
current
}
///|
fn append_unique_import(
entries : Array[String],
entry : String,
) -> Array[String] {
let merged = entries.copy()
for current in merged {
if current == entry {
return merged
}
}
merged.push(entry)
merged
}
///|
fn bind_template_ref_nodes(
nodes : Array[TemplateNode],
resolved_refs : Array[ResolvedTemplateRef],
) -> Array[TemplateNode] {
let bound : Array[TemplateNode] = []
for node in nodes {
bound.push(bind_template_ref_node(node, resolved_refs))
}
bound
}
///|
fn bind_template_ref_node(
node : TemplateNode,
resolved_refs : Array[ResolvedTemplateRef],
) -> TemplateNode {
match node {
Text(_) | Interpolation(_) => node
Element(element) =>
Element(bind_template_ref_element(element, resolved_refs))
Conditional(branches) => {
let next_branches = []
for branch in branches {
next_branches.push({
..branch,
element: bind_template_ref_element(branch.element, resolved_refs),
})
}
Conditional(next_branches)
}
Match(node) => {
let next_branches = []
for branch in node.branches {
next_branches.push({
..branch,
element: bind_template_ref_element(branch.element, resolved_refs),
})
}
Match({ expr: node.expr, branches: next_branches })
}
}
}
///|
fn bind_template_ref_element(
element : TemplateElement,
resolved_refs : Array[ResolvedTemplateRef],
) -> TemplateElement {
let children = bind_template_ref_nodes(element.children, resolved_refs)
let ref_binding_name = match element.ref_static_name {
Some(name) => find_template_ref_binding_name(resolved_refs, name)
None => None
}
{ ..element, children, ref_binding_name }
}
///|
fn find_template_ref_binding_name(
resolved_refs : Array[ResolvedTemplateRef],
name : String,
) -> String? {
for ref_ in resolved_refs {
if ref_.binding_name is Some(binding_name) && ref_.ref_name == Some(name) {
return Some(binding_name)
}
}
None
}
///|
fn validate_template_expr(
expr : String,
binding : String?,
filename : String,
) -> Unit raise CompilerError {
ignore(validate_template_expr_with_ast(expr, binding, filename))
}
///|
fn validate_template_expr_with_ast(
expr : String,
binding : String?,
filename : String,
) -> @mbt_syntax.Expr raise CompilerError {
let parsed = parse_template_expr_ast(expr, filename)
match binding {
Some(binding) =>
if expr_contains_legacy_emit_call(parsed, binding) {
raise CompilerError::InvalidTemplate(
legacy_emit_message(binding, filename),
)
}
None => ()
}
parsed
}
///|
fn legacy_emit_message(binding : String, filename : String) -> String {
"legacy `\{binding}.emit(...` is not supported in \{filename}; use typed event calls like `\{binding}.save()`"
}
///|
fn script_setup_contains_legacy_emit_call(
source : String,
binding : String,
filename : String,
) -> Bool {
let (impls, reports) = @mbt_parser.parse_string(source, name=filename)
if not(reports.is_empty()) {
return false
}
for impl_ in impls {
if impl_contains_legacy_emit_call(impl_, binding) {
return true
}
}
false
}
///|
fn parse_template_expr_ast(
expr : String,
filename : String,
) -> @mbt_syntax.Expr raise CompilerError {
let wrapped = "let __vm_probe = " + expr
let (impls, reports) = @mbt_parser.parse_string(
wrapped,
name=filename + "#template-expr",
)
if not(reports.is_empty()) {
raise CompilerError::InvalidTemplate(
invalid_template_expression_message(expr, filename, reports[0].msg),
)
}
for impl_ in impls {
match impl_ {
TopLetDef(expr~, ..) => return expr
_ => ()
}
}
raise CompilerError::InvalidTemplate(
invalid_template_expression_message(
expr, filename, "failed to parse expression",
),
)
}
///|
fn invalid_template_expression_message(
expr : String,
filename : String,
message : String,
) -> String {
"invalid template expression `\{expr.trim().to_string()}` in \{filename}: \{message}"
}
///|
fn validate_model_target_expr(
expr : @mbt_syntax.Expr,
source : String,
tag : String,
) -> Unit raise CompilerError {
if expr_is_assignable_model_target(expr) ||
expr_is_signal_getter_model_target(expr) {
return
}
raise CompilerError::InvalidDirective(
"v-model requires an assignable target or signal getter on <\{tag}>: `\{source}`",
)
}
///|
fn expr_is_assignable_model_target(expr : @mbt_syntax.Expr) -> Bool {
let expr = unwrap_group_expr_local(expr)
match expr {
Ident(..) => true
Field(record~, ..) => expr_is_assignable_model_target(record)
ArrayGet(array~, ..) => expr_is_assignable_model_target(array)
_ => false
}
}
///|
fn expr_is_signal_getter_model_target(expr : @mbt_syntax.Expr) -> Bool {
let expr = unwrap_group_expr_local(expr)
match expr {
Apply(func~, args~, ..) => is_field_getter_call_model_target(func, args)
DotApply(self~, method_name~, args~, ..) => {
ignore(self)
method_name.name == "get" && argument_list_is_empty_model_target(args)
}
_ => false
}
}
///|
fn is_field_getter_call_model_target(
func : @mbt_syntax.Expr,
args : @list.List[@mbt_syntax.Argument],
) -> Bool {
if not(argument_list_is_empty_model_target(args)) {
return false
}
let func = unwrap_group_expr_local(func)
match func {
Field(record~, accessor~, ..) => {
ignore(record)
accessor_label_name(accessor) == Some("get")
}
_ => false
}
}
///|
fn argument_list_is_empty_model_target(
args : @list.List[@mbt_syntax.Argument],
) -> Bool {
match args {
@list.Empty => true
@list.More(_, ..) => false
}
}
///|
fn impl_contains_legacy_emit_call(
impl_ : @mbt_syntax.Impl,
binding : String,
) -> Bool {
match impl_ {
TopExpr(expr~, ..) | TopTest(expr~, ..) | TopLetDef(expr~, ..) =>
expr_contains_legacy_emit_call(expr, binding)
TopFuncDef(decl_body~, ..) =>
decl_body_contains_legacy_emit_call(decl_body, binding)
TopImpl(body~, ..) => decl_body_contains_legacy_emit_call(body, binding)
TopView(body~, ..) => expr_contains_legacy_emit_call(body, binding)
TopTypeDef(_) | TopTrait(_) | TopImplRelation(..) | _ => false
}
}
///|
fn decl_body_contains_legacy_emit_call(
body : @mbt_syntax.DeclBody,
binding : String,
) -> Bool {
match body {
DeclBody(expr~, ..) => expr_contains_legacy_emit_call(expr, binding)
DeclStubs(_) | DeclNone => false
}
}
///|
fn expr_contains_legacy_emit_call(
expr : @mbt_syntax.Expr,
binding : String,
) -> Bool {
let expr = unwrap_group_expr_local(expr)
match expr {
Apply(func~, args~, ..) =>
is_legacy_emit_callee(func, binding) ||
expr_contains_legacy_emit_call(func, binding) ||
argument_list_contains_legacy_emit_call(args, binding)
Infix(lhs~, rhs~, ..) =>
expr_contains_legacy_emit_call(lhs, binding) ||
expr_contains_legacy_emit_call(rhs, binding)
Unary(expr~, ..) => expr_contains_legacy_emit_call(expr, binding)
Array(exprs~, ..) | Tuple(exprs~, ..) =>
expr_list_contains_legacy_emit_call(exprs, binding)
Continue(args~, ..) => expr_list_contains_legacy_emit_call(args, binding)
ArraySpread(elems~, ..) =>
spreadable_exprs_contain_legacy_emit_call(elems, binding)
ArrayGet(array~, index~, ..) =>
expr_contains_legacy_emit_call(array, binding) ||
expr_contains_legacy_emit_call(index, binding)
ArrayGetSlice(array~, start_index~, end_index~, ..) =>
expr_contains_legacy_emit_call(array, binding) ||
expr_option_contains_legacy_emit_call(start_index, binding) ||
expr_option_contains_legacy_emit_call(end_index, binding)
ArraySet(array~, index~, value~, ..) =>
expr_contains_legacy_emit_call(array, binding) ||
expr_contains_legacy_emit_call(index, binding) ||
expr_contains_legacy_emit_call(value, binding)
ArrayAugmentedSet(array~, index~, value~, ..) =>
expr_contains_legacy_emit_call(array, binding) ||
expr_contains_legacy_emit_call(index, binding) ||
expr_contains_legacy_emit_call(value, binding)
Constant(..) | Constr(..) | Ident(..) | Method(..) | Hole(..) | Unit(..) =>
false
MultilineString(elems~, ..) =>
multiline_string_elems_contain_legacy_emit_call(elems, binding)
Interp(elems~, ..) => interp_elems_contain_legacy_emit_call(elems, binding)
Constraint(expr~, ..) => expr_contains_legacy_emit_call(expr, binding)
As(expr~, ..) => expr_contains_legacy_emit_call(expr, binding)
Assign(expr~, ..) => expr_contains_legacy_emit_call(expr, binding)
Raise(err_value~, ..) => expr_contains_legacy_emit_call(err_value, binding)
TryOperator(body~, ..) => expr_contains_legacy_emit_call(body, binding)
Group(expr~, ..) => expr_contains_legacy_emit_call(expr, binding)
While(loop_cond~, loop_body~, while_else~, ..) =>
expr_contains_legacy_emit_call(loop_cond, binding) ||
expr_contains_legacy_emit_call(loop_body, binding) ||
expr_option_contains_legacy_emit_call(while_else, binding)
Function(func~, ..) => func_contains_legacy_emit_call(func, binding)
If(cond~, ifso~, ifnot~, ..) =>
expr_contains_legacy_emit_call(cond, binding) ||
expr_contains_legacy_emit_call(ifso, binding) ||
expr_option_contains_legacy_emit_call(ifnot, binding)
Guard(cond~, otherwise~, body~, ..) =>
expr_contains_legacy_emit_call(cond, binding) ||
expr_option_contains_legacy_emit_call(otherwise, binding) ||
expr_contains_legacy_emit_call(body, binding)
Is(expr~, ..) | IsLexMatch(expr~, ..) =>
expr_contains_legacy_emit_call(expr, binding)
Defer(expr~, body~, ..) =>
expr_contains_legacy_emit_call(expr, binding) ||
expr_contains_legacy_emit_call(body, binding)
Let(expr~, body~, ..) =>
expr_contains_legacy_emit_call(expr, binding) ||
expr_contains_legacy_emit_call(body, binding)
LetMut(expr~, body~, ..) =>
expr_contains_legacy_emit_call(expr, binding) ||
expr_contains_legacy_emit_call(body, binding)
Pipe(lhs~, rhs~, ..) =>
expr_contains_legacy_emit_call(lhs, binding) ||
expr_contains_legacy_emit_call(rhs, binding)
LetFn(func~, body~, ..) =>
func_contains_legacy_emit_call(func, binding) ||
expr_contains_legacy_emit_call(body, binding)
LetRec(bindings~, body~, ..) =>
function_binding_list_contains_legacy_emit_call(bindings, binding) ||
expr_contains_legacy_emit_call(body, binding)
LetAnd(bindings~, body~, ..) =>
typed_function_binding_list_contains_legacy_emit_call(bindings, binding) ||
expr_contains_legacy_emit_call(body, binding)
Sequence(exprs~, last_expr~, ..) =>
expr_list_contains_legacy_emit_call(exprs, binding) ||
expr_contains_legacy_emit_call(last_expr, binding)
Record(fields~, ..) => field_defs_contain_legacy_emit_call(fields, binding)
RecordUpdate(record~, fields~, ..) =>
expr_contains_legacy_emit_call(record, binding) ||
field_defs_contain_legacy_emit_call(fields, binding)
Field(record~, ..) => expr_contains_legacy_emit_call(record, binding)
DotApply(self~, method_name~, args~, ..) =>
(is_binding_expr(self, binding) && method_name.name == "emit") ||
expr_contains_legacy_emit_call(self, binding) ||
argument_list_contains_legacy_emit_call(args, binding)
Mutate(record~, field~, ..) =>
expr_contains_legacy_emit_call(record, binding) ||
expr_contains_legacy_emit_call(field, binding)
Match(expr~, cases~, ..) =>
expr_contains_legacy_emit_call(expr, binding) ||
case_list_contains_legacy_emit_call(cases, binding)
LexMatch(expr~, cases~, ..) =>
expr_contains_legacy_emit_call(expr, binding) ||
lex_case_list_contains_legacy_emit_call(cases, binding)
Return(return_value~, ..) =>
expr_option_contains_legacy_emit_call(return_value, binding)
Break(arg~, ..) => expr_option_contains_legacy_emit_call(arg, binding)
Loop(arg~, body~, ..) =>
expr_contains_legacy_emit_call(arg, binding) ||
case_list_contains_legacy_emit_call(body, binding)
For(
binders~,
condition~,
continue_block~,
body~,
for_else~,
where_clause~,
..
) =>
binder_expr_pairs_contain_legacy_emit_call(binders, binding) ||
expr_option_contains_legacy_emit_call(condition, binding) ||
binder_expr_pairs_contain_legacy_emit_call(continue_block, binding) ||
expr_contains_legacy_emit_call(body, binding) ||
expr_option_contains_legacy_emit_call(for_else, binding) ||
where_clause_contains_legacy_emit_call(where_clause, binding)
ForEach(expr~, body~, else_block~, ..) =>
expr_contains_legacy_emit_call(expr, binding) ||
expr_contains_legacy_emit_call(body, binding) ||
expr_option_contains_legacy_emit_call(else_block, binding)
Try(body~, catch_~, try_else~, ..) =>
expr_contains_legacy_emit_call(body, binding) ||
case_list_contains_legacy_emit_call(catch_, binding) ||
case_list_option_contains_legacy_emit_call(try_else, binding)
Map(elems~, ..) => map_expr_elems_contain_legacy_emit_call(elems, binding)
StaticAssert(body~, ..) => expr_contains_legacy_emit_call(body, binding)
}
}
///|
fn unwrap_group_expr_local(expr : @mbt_syntax.Expr) -> @mbt_syntax.Expr {
match expr {
Group(expr~, ..) => unwrap_group_expr_local(expr)
_ => expr
}
}
///|
fn is_legacy_emit_callee(func : @mbt_syntax.Expr, binding : String) -> Bool {
let func = unwrap_group_expr_local(func)
match func {
Field(record~, accessor~, ..) =>
is_binding_expr(record, binding) &&
accessor_label_name(accessor) == Some("emit")
_ => false
}
}
///|
fn is_binding_expr(expr : @mbt_syntax.Expr, binding : String) -> Bool {
let expr = unwrap_group_expr_local(expr)
match expr {
Ident(id~, ..) => long_ident_matches_binding(id.name, binding)
_ => false
}
}
///|
fn long_ident_matches_binding(
ident : @mbt_syntax.LongIdent,
binding : String,
) -> Bool {
match ident {
Ident(name~) => name == binding
Dot(..) => false
}
}
///|
fn accessor_label_name(accessor : @mbt_syntax.Accessor) -> String? {
match accessor {
Label(label) => Some(label.name)
Index(..) | Newtype(..) => None
}
}
///|
fn func_contains_legacy_emit_call(
func : @mbt_syntax.Func,
binding : String,
) -> Bool {
expr_contains_legacy_emit_call(func.body, binding)
}
///|
fn expr_list_contains_legacy_emit_call(
exprs : @list.List[@mbt_syntax.Expr],
binding : String,
) -> Bool {
for expr in exprs {
if expr_contains_legacy_emit_call(expr, binding) {
return true
}
}
false
}
///|
fn expr_option_contains_legacy_emit_call(
expr : @mbt_syntax.Expr?,
binding : String,
) -> Bool {
match expr {
Some(expr) => expr_contains_legacy_emit_call(expr, binding)
None => false
}
}
///|
fn argument_list_contains_legacy_emit_call(
args : @list.List[@mbt_syntax.Argument],
binding : String,
) -> Bool {
for arg in args {
if expr_contains_legacy_emit_call(arg.value, binding) {
return true
}
}
false
}
///|
fn spreadable_exprs_contain_legacy_emit_call(
elems : @list.List[@mbt_syntax.SpreadableElem],
binding : String,
) -> Bool {
for elem in elems {
match elem {
Regular(expr) | Spread(expr~, ..) =>
if expr_contains_legacy_emit_call(expr, binding) {
return true
}
}
}
false
}
///|
fn field_defs_contain_legacy_emit_call(
fields : @list.List[@mbt_syntax.FieldDef],
binding : String,
) -> Bool {
for field in fields {
if expr_contains_legacy_emit_call(field.expr, binding) {
return true
}
}
false
}
///|
fn case_list_contains_legacy_emit_call(
cases : @list.List[@mbt_syntax.Case],
binding : String,
) -> Bool {
for case_ in cases {
if expr_option_contains_legacy_emit_call(case_.guard_, binding) ||
expr_contains_legacy_emit_call(case_.body, binding) {
return true
}
}
false
}
///|
fn case_list_option_contains_legacy_emit_call(
cases : @list.List[@mbt_syntax.Case]?,
binding : String,
) -> Bool {
match cases {
Some(cases) => case_list_contains_legacy_emit_call(cases, binding)
None => false
}
}
///|
fn lex_case_list_contains_legacy_emit_call(
cases : @list.List[@mbt_syntax.LexCase],
binding : String,
) -> Bool {
for case_ in cases {
if expr_contains_legacy_emit_call(case_.body, binding) {
return true
}
}
false
}
///|
fn binder_expr_pairs_contain_legacy_emit_call(
bindings : @list.List[(@mbt_syntax.Binder, @mbt_syntax.Expr)],
binding : String,
) -> Bool {
for entry in bindings {
if expr_contains_legacy_emit_call(entry.1, binding) {
return true
}
}
false
}
///|
fn function_binding_list_contains_legacy_emit_call(
bindings : @list.List[(@mbt_syntax.Binder, @mbt_syntax.Func)],
binding : String,
) -> Bool {
for entry in bindings {
if func_contains_legacy_emit_call(entry.1, binding) {
return true
}
}
false
}
///|
fn typed_function_binding_list_contains_legacy_emit_call(
bindings : @list.List[
(@mbt_syntax.Binder, @mbt_syntax.Type?, @mbt_syntax.Func),
],
binding : String,
) -> Bool {
for entry in bindings {
if func_contains_legacy_emit_call(entry.2, binding) {
return true
}
}
false
}
///|
fn where_clause_contains_legacy_emit_call(
clause : @mbt_syntax.WhereClause?,
binding : String,
) -> Bool {
match clause {
Some(clause) => field_defs_contain_legacy_emit_call(clause.fields, binding)
None => false
}
}
///|
fn map_expr_elems_contain_legacy_emit_call(
elems : @list.List[@mbt_syntax.MapExprElem],
binding : String,
) -> Bool {
for elem in elems {
if expr_contains_legacy_emit_call(elem.expr, binding) {
return true
}
}
false
}
///|
fn interp_elems_contain_legacy_emit_call(
elems : @list.List[@mbt_syntax.InterpElem],
binding : String,
) -> Bool {
for elem in elems {
match elem {
Expr(expr~, ..) =>
if expr_contains_legacy_emit_call(expr, binding) {
return true
}
Literal(..) | Source(_) => ()
}
}
false
}
///|
fn multiline_string_elems_contain_legacy_emit_call(
elems : @list.List[@mbt_syntax.MultilineStringElem],
binding : String,
) -> Bool {
for elem in elems {
match elem {
String(_) => ()
Interp(interp_elems) =>
if interp_elems_contain_legacy_emit_call(interp_elems, binding) {
return true
}
}
}
false
}