wasm-webidl-bindings-text-parser 0.1.0

Raw WebIDL bindings text encoder/decoder. Still in a state of flux!
Documentation
use std::str::FromStr;
use crate::error::error;
use crate::lexer::Token;

grammar<'input, A>(input: &'input str, actions: &mut A)
    where A: crate::Actions;

pub(crate) WebidlBindingsSection: A::WebidlBindingsSection =
    <types:WebidlTypeSubsection> <bindings:WebidlFunctionBindingsSubsection> =>
        actions.webidl_bindings_section(types, bindings);

WebidlTypeSubsection: A::WebidlTypeSubsection =
    <types:WebidlType*> => actions.webidl_type_subsection(types);

pub(crate) WebidlType: A::WebidlType =
    "type" <name:Identifier?> <ty:WebidlCompoundType> =>
        actions.webidl_type(name, ty);

WebidlCompoundType: A::WebidlCompoundType = {
    <a:WebidlFunction> => a.into(),
    <a:WebidlDictionary> => a.into(),
    <a:WebidlEnumeration> => a.into(),
    <a:WebidlUnion> => a.into(),
};

WebidlFunction: A::WebidlFunction = {
    "("
        "func"
        <kind:WebidlFunctionKind?>
        <params:WebidlFunctionParams?>
        <result:WebidlFunctionResult?>
    ")" => actions.webidl_function(kind, params, result),
};

WebidlFunctionKind: A::WebidlFunctionKind = {
    <a:WebidlFunctionKindMethod> => a.into(),
    <a:WebidlFunctionKindConstructor> => a.into(),
    // NB: functions that lack a kind are implicitly static.
};

WebidlFunctionKindMethod: A::WebidlFunctionKindMethod =
    "(" "method" <ty:WebidlTypeRef> ")" =>
        actions.webidl_function_kind_method(ty);

WebidlFunctionKindConstructor: A::WebidlFunctionKindConstructor = {
    "(" "constructor" "default-new-target" ")" =>
        actions.webidl_function_kind_constructor_default_new_target(),
    // TODO: What are the non-default target forms?
};

WebidlFunctionParams: A::WebidlFunctionParams =
    "(" "param" <tys:WebidlTypeRef*> ")" =>
        actions.webidl_function_params(tys);

WebidlFunctionResult: A::WebidlFunctionResult =
    "(" "result" <ty:WebidlTypeRef> ")" =>
        actions.webidl_function_result(ty);

WebidlDictionary: A::WebidlDictionary =
    "(" "dict" <fields:WebidlDictionaryField*> ")" =>
        actions.webidl_dictionary(fields);

WebidlDictionaryField: A::WebidlDictionaryField =
    "(" "field" <name:WebidlDictionaryFieldName> <ty:WebidlTypeRef> ")" =>
        actions.webidl_dictionary_field(name, ty);

WebidlDictionaryFieldName: A::WebidlDictionaryFieldName =
    <name:QuotedString> =>
        actions.webidl_dictionary_field_name(&name[1..(name.len() - 1)]);

WebidlEnumeration: A::WebidlEnumeration =
    "(" "enum" <values:WebidlEnumerationValue*> ")" =>
        actions.webidl_enumeration(values);

WebidlEnumerationValue: A::WebidlEnumerationValue =
    <value:QuotedString> =>
        actions.webidl_enumeration_value(&value[1..(value.len() - 1)]);

WebidlUnion: A::WebidlUnion =
    "(" "union" <members:WebidlTypeRef*> ")" =>
        actions.webidl_union(members);

WebidlFunctionBindingsSubsection: A::WebidlFunctionBindingsSubsection =
    <bindings:FunctionBinding*>
    <binds:Bind*> =>
        actions.webidl_function_bindings_subsection(bindings, binds);

FunctionBinding: A::FunctionBinding = {
    <a:ImportBinding> => a.into(),
    <a:ExportBinding> => a.into(),
};

pub(crate) ImportBinding: A::ImportBinding =
    "func-binding"
    <name:Identifier?>
    "import"
    <wasm_ty:WasmFuncTypeRef>
    <webidl_ty:WebidlTypeRef>
    <webidl_params:("(" "param" OutgoingBindingMap ")")?>
    <webidl_result:("(" "result" IncomingBindingMap ")")?> =>
        actions.import_binding(
            name,
            wasm_ty,
            webidl_ty,
            webidl_params.map(|params| params.2),
            webidl_result.map(|result| result.2),
        );

pub(crate) ExportBinding: A::ExportBinding =
    "func-binding"
    <name:Identifier?>
    "export"
    <wasm_ty:WasmFuncTypeRef>
    <webidl_ty:WebidlTypeRef>
    <webidl_params:("(" "param" IncomingBindingMap ")")?>
    <webidl_result:("(" "result" OutgoingBindingMap ")")?> =>
        actions.export_binding(
            name,
            wasm_ty,
            webidl_ty,
            webidl_params.map(|params| params.2),
            webidl_result.map(|result| result.2),
        );

pub(crate) Bind: A::Bind =
    "bind" <func:WasmFuncRef> <binding:BindingRef> =>
        actions.bind(func, binding);

OutgoingBindingMap: A::OutgoingBindingMap =
    <bindings:OutgoingBindingExpression*> =>
        actions.outgoing_binding_map(bindings);

IncomingBindingMap: A::IncomingBindingMap =
    <bindings:IncomingBindingExpression*> =>
        actions.incoming_binding_map(bindings);

pub(crate) WebidlTypeRef: A::WebidlTypeRef = {
    "type="? <a:WebidlTypeRefNamed> => a.into(),
    "type="? <a:WebidlTypeRefIndexed> => a.into(),
    "type="? <a:WebidlScalarType> => a.into(),
};

WebidlTypeRefNamed: A::WebidlTypeRefNamed =
    <s:Identifier> =>? {
        actions
            .webidl_type_ref_named(s)
            .ok_or_else(|| error(format!("unknown Web IDL type name: '{}'", s)))
    };

WebidlTypeRefIndexed: A::WebidlTypeRefIndexed =
    <idx:Unsigned> =>? {
        actions
            .webidl_type_ref_indexed(idx)
            .ok_or_else(|| error(format!("unknown Web IDL type index: {}", idx)))
    };

pub(crate) WebidlIndex: u32 = "idx="? <Unsigned>;

WebidlScalarType: A::WebidlScalarType = {
    "any" => actions.webidl_scalar_type_any(),
    "boolean" => actions.webidl_scalar_type_boolean(),
    "byte" => actions.webidl_scalar_type_byte(),
    "octet" => actions.webidl_scalar_type_octet(),
    "long" => actions.webidl_scalar_type_long(),
    "unsigned long" => actions.webidl_scalar_type_unsigned_long(),
    "short" => actions.webidl_scalar_type_short(),
    "unsigned short" => actions.webidl_scalar_type_unsigned_short(),
    "long long" => actions.webidl_scalar_type_long_long(),
    "unsigned long long" => actions.webidl_scalar_type_unsigned_long_long(),
    "float" => actions.webidl_scalar_type_float(),
    "unrestricted float" => actions.webidl_scalar_type_unrestricted_float(),
    "double" => actions.webidl_scalar_type_double(),
    "unrestricted double" => actions.webidl_scalar_type_unrestricted_double(),
    "DOMString" => actions.webidl_scalar_type_dom_string(),
    "ByteString" => actions.webidl_scalar_type_byte_string(),
    "USVString" => actions.webidl_scalar_type_usv_string(),
    "object" => actions.webidl_scalar_type_object(),
    "symbol" => actions.webidl_scalar_type_symbol(),

    // "Scalar" arrays.
    "ArrayBuffer" => actions.webidl_scalar_type_array_buffer(),
    "DataView" => actions.webidl_scalar_type_data_view(),
    "Int8Array" => actions.webidl_scalar_type_int8_array(),
    "Int16Array" => actions.webidl_scalar_type_int16_array(),
    "Int32Array" => actions.webidl_scalar_type_int32_array(),
    "Uint8Array" => actions.webidl_scalar_type_uint8_array(),
    "Uint16Array" => actions.webidl_scalar_type_uint16_array(),
    "Uint32Array" => actions.webidl_scalar_type_uint32_array(),
    "Uint8ClampedArray" => actions.webidl_scalar_type_uint8_clamped_array(),
    "Float32Array" => actions.webidl_scalar_type_float32_array(),
    "Float64Array" => actions.webidl_scalar_type_float64_array(),
};

pub(crate) WasmValType: A::WasmValType = {
    "i32" => actions.wasm_val_type_i32(),
    "i64" => actions.wasm_val_type_i64(),
    "f32" => actions.wasm_val_type_f32(),
    "f64" => actions.wasm_val_type_f64(),
    "v128" => actions.wasm_val_type_v128(),
    "anyref" => actions.wasm_val_type_anyref(),
};

pub(crate) WasmFuncTypeRef: A::WasmFuncTypeRef = {
    <a:WasmFuncTypeRefNamed> => a.into(),
    <a:WasmFuncTypeRefIndexed> => a.into(),
};

WasmFuncTypeRefNamed: A::WasmFuncTypeRefNamed =
    <s:Identifier> =>? {
        actions
            .wasm_func_type_ref_named(s)
            .ok_or_else(|| error(format!("unknown Wasm function type name: '{}'", s)))
    };

WasmFuncTypeRefIndexed: A::WasmFuncTypeRefIndexed =
    <idx:Unsigned> =>? {
        actions
            .wasm_func_type_ref_indexed(idx)
            .ok_or_else(|| error(format!("unknown Wasm function type index: {}", idx)))
    };

pub(crate) WasmFuncRef: A::WasmFuncRef = {
    <a:WasmFuncRefNamed> => a.into(),
    <a:WasmFuncRefIndexed> => a.into(),
};

WasmFuncRefNamed: A::WasmFuncRefNamed =
    <s:Identifier> =>? {
        actions
            .wasm_func_ref_named(s)
            .ok_or_else(|| error(format!("unknown Wasm function name: '{}'", s)))
    };

WasmFuncRefIndexed: A::WasmFuncRefIndexed =
    <idx:Unsigned> =>? {
        actions
            .wasm_func_ref_indexed(idx)
            .ok_or_else(|| error(format!("unknown Wasm function index: {}", idx)))
    };

pub(crate) BindingRef: A::BindingRef = {
    <a:BindingRefNamed> => a.into(),
    <a:BindingRefIndexed> => a.into(),
};

BindingRefNamed: A::BindingRefNamed =
    <s:Identifier> =>? {
        actions
            .binding_ref_named(s)
            .ok_or_else(|| error(format!("unknown function binding name: '{}'", s)))
    };

BindingRefIndexed: A::BindingRefIndexed =
    <idx:Unsigned> =>? {
        actions
            .binding_ref_indexed(idx)
            .ok_or_else(|| error(format!("unknown function binding index: {}", idx)))
    };

pub(crate) OutgoingBindingExpression: A::OutgoingBindingExpression = {
    <a:OutgoingBindingExpressionAs> => a.into(),
    <a:OutgoingBindingExpressionUtf8Str> => a.into(),
    <a:OutgoingBindingExpressionUtf8CStr> => a.into(),
    <a:OutgoingBindingExpressionI32ToEnum> => a.into(),
    <a:OutgoingBindingExpressionView> => a.into(),
    <a:OutgoingBindingExpressionCopy> => a.into(),
    <a:OutgoingBindingExpressionDict> => a.into(),
    <a:OutgoingBindingExpressionBindExport> => a.into(),
};

OutgoingBindingExpressionAs: A::OutgoingBindingExpressionAs =
    "(" "as" <ty:WebidlTypeRef> <idx:WebidlIndex> ")" =>
        actions.outgoing_binding_expression_as(ty, idx);

OutgoingBindingExpressionUtf8Str: A::OutgoingBindingExpressionUtf8Str =
    "(" "utf8-str" <ty:WebidlTypeRef> <offset:Unsigned> <length:Unsigned> ")" =>
        actions.outgoing_binding_expression_utf8_str(ty, offset, length);

OutgoingBindingExpressionUtf8CStr: A::OutgoingBindingExpressionUtf8CStr =
    "(" "utf8-cstr" <ty:WebidlTypeRef> <offset:Unsigned> ")" =>
        actions.outgoing_binding_expression_utf8_c_str(ty, offset);

OutgoingBindingExpressionI32ToEnum: A::OutgoingBindingExpressionI32ToEnum =
    "(" "i32-to-enum" <ty:WebidlTypeRef> <idx:WebidlIndex> ")" =>
        actions.outgoing_binding_expression_i32_to_enum(ty, idx);

OutgoingBindingExpressionView: A::OutgoingBindingExpressionView =
    "(" "view" <ty:WebidlTypeRef> <offset:Unsigned> <length:Unsigned> ")" =>
        actions.outgoing_binding_expression_view(ty, offset, length);

OutgoingBindingExpressionCopy: A::OutgoingBindingExpressionCopy =
    "(" "copy" <ty:WebidlTypeRef> <offset:Unsigned> <length:Unsigned> ")" =>
        actions.outgoing_binding_expression_copy(ty, offset, length);

OutgoingBindingExpressionDict: A::OutgoingBindingExpressionDict =
    "(" "dict" <ty:WebidlTypeRef> <fields:OutgoingBindingExpression*> ")" =>
        actions.outgoing_binding_expression_dict(ty, fields);

OutgoingBindingExpressionBindExport: A::OutgoingBindingExpressionBindExport =
    "("
        "bind-export"
        <ty:WebidlTypeRef>
        <binding:BindingRef>
        <idx:Unsigned>
    ")" =>
        actions.outgoing_binding_expression_bind_export(ty, binding, idx);

pub(crate) IncomingBindingExpression: A::IncomingBindingExpression = {
    <a:IncomingBindingExpressionGet> => a.into(),
    <a:IncomingBindingExpressionAs> => a.into(),
    <a:IncomingBindingExpressionAllocUtf8Str> => a.into(),
    <a:IncomingBindingExpressionAllocCopy> => a.into(),
    <a:IncomingBindingExpressionEnumToI32> => a.into(),
    <a:IncomingBindingExpressionField> => a.into(),
    <a:IncomingBindingExpressionBindImport> => a.into(),
};

IncomingBindingExpressionGet: A::IncomingBindingExpressionGet =
    "(" "get" <idx:WebidlIndex> ")" =>
        actions.incoming_binding_expression_get(idx);

IncomingBindingExpressionAs: A::IncomingBindingExpressionAs =
    "(" "as" <ty:WasmValType> <expr:IncomingBindingExpression> ")" =>
        actions.incoming_binding_expression_as(ty, expr);

IncomingBindingExpressionAllocUtf8Str: A::IncomingBindingExpressionAllocUtf8Str =
    "("
        "alloc-utf8-str"
        <alloc_func_name:Identifier>
        <expr:IncomingBindingExpression>
    ")" =>
        actions.incoming_binding_expression_alloc_utf8_str(alloc_func_name, expr);

IncomingBindingExpressionAllocCopy: A::IncomingBindingExpressionAllocCopy =
    "("
        "alloc-copy"
        <alloc_func_name:Identifier>
        <expr:IncomingBindingExpression>
    ")" =>
        actions.incoming_binding_expression_alloc_copy(alloc_func_name, expr);

IncomingBindingExpressionEnumToI32: A::IncomingBindingExpressionEnumToI32 =
    "(" "enum-to-i32" <ty:WebidlTypeRef> <expr:IncomingBindingExpression> ")" =>
        actions.incoming_binding_expression_enum_to_i32(ty, expr);

IncomingBindingExpressionField: A::IncomingBindingExpressionField =
    "(" "field" <idx:Unsigned> <expr:IncomingBindingExpression> ")" =>
        actions.incoming_binding_expression_field(idx, expr);

IncomingBindingExpressionBindImport: A::IncomingBindingExpressionBindImport =
    "("
        "bind-import"
        <ty:WasmFuncTypeRef>
        <binding:BindingRef>
        <expr:IncomingBindingExpression>
    ")" =>
        actions.incoming_binding_expression_bind_import(ty, binding, expr);

Unsigned: u32 = <s:r"[0-9]+"> => u32::from_str(s).unwrap();

Identifier: &'input str = <r"[a-zA-Z$][a-zA-Z0-9$_]*">;

QuotedString: &'input str = <r#""(([^\\"]|\\.)*)""#>;

extern {
    type Location = usize;
    type Error = String;

    enum Token<'input> {
        "(" => Token::LeftParenthesis,
        ")" => Token::RightParenthesis,
        "ArrayBuffer" => Token::ArrayBuffer,
        "ByteString" => Token::ByteString,
        "DOMString" => Token::DOMString,
        "DataView" => Token::DataView,
        "Float32Array" => Token::Float32Array,
        "Float64Array" => Token::Float64Array,
        "Int16Array" => Token::Int16Array,
        "Int32Array" => Token::Int32Array,
        "Int8Array" => Token::Int8Array,
        "USVString" => Token::USVString,
        "Uint16Array" => Token::Uint16Array,
        "Uint32Array" => Token::Uint32Array,
        "Uint8Array" => Token::Uint8Array,
        "Uint8ClampedArray" => Token::Uint8ClampedArray,
        "alloc-copy" => Token::AllocCopy,
        "alloc-utf8-cstr" => Token::AllocUtf8CStr,
        "alloc-utf8-str" => Token::AllocUtf8Str,
        "any" => Token::Any,
        "anyref" => Token::Anyref,
        "as" => Token::As,
        "bind" => Token::Bind,
        "bind-export" => Token::BindExport,
        "bind-import" => Token::BindImport,
        "boolean" => Token::Boolean,
        "byte" => Token::Byte,
        "constructor" => Token::Constructor,
        "copy" => Token::Copy,
        "default-new-target" => Token::DefaultNewTarget,
        "dict" => Token::Dict,
        "double" => Token::Double,
        "enum" => Token::Enum,
        "enum-to-i32" => Token::EnumToI32,
        "export" => Token::Export,
        "f32" => Token::F32,
        "f64" => Token::F64,
        "field" => Token::Field,
        "float" => Token::Float,
        "func" => Token::Func,
        "func-binding" => Token::FuncBinding,
        "get" => Token::Get,
        "i32" => Token::I32,
        "i32-to-enum" => Token::I32ToEnum,
        "i64" => Token::I64,
        "idx=" => Token::Index,
        "import" => Token::Import,
        "long long" => Token::LongLong,
        "long" => Token::Long,
        "method" => Token::Method,
        "object" => Token::Object,
        "octet" => Token::Octet,
        "param" => Token::Param,
        "result" => Token::Result,
        "short" => Token::Short,
        "symbol" => Token::Symbol,
        "type=" => Token::TypeRef,
        "type" => Token::Type,
        "union" => Token::Union,
        "unrestricted double" => Token::UnrestrictedDouble,
        "unrestricted float" => Token::UnrestrictedFloat,
        "unsigned long long" => Token::UnsignedLongLong,
        "unsigned long" => Token::UnsignedLong,
        "unsigned short" => Token::UnsignedShort,
        "utf8-cstr" => Token::Utf8CStr,
        "utf8-str" => Token::Utf8Str,
        "v128" => Token::V128,
        "view" => Token::View,
        r"[0-9]+" => Token::Unsigned(<&'input str>),
        r"[a-zA-Z$][a-zA-Z0-9$_]*" => Token::Identifier(<&'input str>),
        r#""(([^\\"]|\\.)*)""# => Token::QuotedString(<&'input str>),
    }
}