1 unstable release

Uses new Rust 2024

new 0.0.6-rc.1 Apr 26, 2025

#148 in Robotics

MIT/Apache

115KB
4K SLoC

Beet RSX Combinator

JSX-like parser combinator for Rust.

This crate is a fork of Victor Porof's rsx-parser

Purpose

This is an experimental parser for JSX-like code in Rust. The long term goal might be to build "something like React" in Rust, but this can mean a number of things, from a direct port with 100% API compatibility to a completely different product. A JSX-like parser is a good and simple place to start experimenting from.

RSX vs. JSX

The JSX spec is, although a draft, presumably stable. Syntax extension equivalents can be found for Rust, which is the main scope of this experiment.

Example, inspired from the JSX spec website linked above:

const FunDropdown = (props) =>
  <Dropdown show={props.visible}>
    A dropdown list
    <Menu
      icon={props.menu.icon}
      onHide={(e) => console.log(e)}
      onShow={(e) => console.log(e)}
    >
      <MenuItem>Do Something</MenuItem>
      {
        shouldDoSomethingFun()
          ? <MenuItem>Do Something Fun!</MenuItem>
          : <MenuItem>Do Something Else</MenuItem>
      }
    </Menu>
  </Dropdown>;

An equivalent interpretation of JSX in Rust, using compiler plugins, looks this:

fn fun_dropdown(props: Props) -> RSXElement {
  rsx! {
    <Dropdown show={props.visible}>
      A dropdown list
      <Menu
        icon={props.menu.icon}
        onHide={|e: Event| println!("{:?}", e)}
        onShow={|e: Event| println!("{:?}", e)}
      >
        <MenuItem>Do Something</MenuItem>
        {
          if should_do_something_fun() {
            <MenuItem>Do Something Fun!</MenuItem>
          } else {
            <MenuItem>Do Something Else</MenuItem>
          }
        }
      </Menu>
    </Dropdown>
  }
}

Supported grammar

All of the JSX official grammar is supported. In the case of handling arbitrary Rust code inside RSX, the treatment is similar: JSX can contain JavaScript "code blocks" delimited by curly braces (specifically "assignment expressions"), in clearly defined locations such as attribute values, children contents etc. Rust expressions provide sufficient equivalence.

PrimaryExpression

  • JSXElement

Elements

JSXElement

  • JSXSelfClosingElement
  • JSXOpeningElement JSXChildren? JSXClosingElement

JSXSelfClosingElement

  • < JSXElementName JSXAttributes? / >

JSXOpeningElement

  • < JSXElementName JSXAttributes? >

JSXClosingElement

  • < / JSXElementName >

JSXElementName

  • JSXIdentifier
  • JSXNamedspacedName
  • JSXMemberExpression

JSXIdentifier

  • IdentifierStart
  • JSXIdentifier IdentifierPart
  • JSXIdentifier -

JSXNamespacedName

  • JSXIdentifier : JSXIdentifier

JSXMemberExpression

  • JSXIdentifier . JSXIdentifier
  • JSXMemberExpression . JSXIdentifier

Attributes

JSXAttributes

  • JSXSpreadAttribute JSXAttributes?
  • JSXAttribute JSXAttributes?

JSXSpreadAttribute

  • { ... AssignmentExpression }

JSXAttribute

  • JSXAttributeName = JSXAttributeValue

JSXAttributeName

  • JSXIdentifier
  • JSXNamespacedName

JSXAttributeValue

  • " JSXDoubleStringCharacters? "
  • ' JSXSingleStringCharacters? '
  • { AssignmentExpression }
  • JSXElement

JSXDoubleStringCharacters

  • JSXDoubleStringCharacter JSXDoubleStringCharacters?

JSXDoubleStringCharacter

  • SourceCharacter but not "

JSXSingleStringCharacters

  • JSXSingleStringCharacter JSXSingleStringCharacters?

JSXSingleStringCharacter

  • SourceCharacter but not '

Children

JSXChildren

  • JSXChild JSXChildren?

JSXChild

  • JSXText
  • JSXElement
  • { AssignmentExpression? }

JSXText

  • JSXTextCharacter JSXText?

JSXTextCharacter

  • SourceCharacter but not one of {, <, > or }

License

Copyright 2016 Mozilla Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Dependencies

~2.7–5MB
~93K SLoC