Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • S sweet-core
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 62
    • Issues 62
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 4
    • Merge requests 4
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Infrastructure Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • sweet-js
  • sweet-core
  • Merge requests
  • !244

invoke/invokeOnce pattern classes, identity rules, throwSyntaxCaseError

  • Review changes

  • Download
  • Email patches
  • Plain diff
Merged Administrator requested to merge github/fork/natefaubion/pattern-macros-2 into master Feb 06, 2014
  • Overview 9
  • Commits 8
  • Pipelines 0
  • Changes 6

Created by: natefaubion

This PR contains a few related features:

invoke and invokeOnce

This is a new pattern class that actually lets you invoke another macro as a pattern class. It sounds a bit weird at first, but it's actually really powerful! It basically inserts the provided macro into the token stream, expands it, and assigns the result to the pattern variable. If the macro fails to match, it fails the invoking rule, just like any other pattern class. Here's an example that matches functions:

macro func {
  rule { function ($args (,) ...) { $body ... } } => {
    function ($args (,) ...) { $body ... }
  }
  rule { function $name:ident ($args (,) ...) { $body ... } } => {
    function $name ($args (,) ...) { $body ... }
  }
}

macro checkFunc {
  rule { $f:invoke(func) } => {
    $f
  }
}

checkFunc function foo() {} // works
checkFunc 12 // fails

It turns out you can encode all sorts of things with this pattern: alternates, optional tokens, a keyword class, a numeric class. You can even write something to circumvent ASI (examples). In fact, you could actually write all the built in classes using this form.

The difference between invoke and invokeOnce is that invoke will keep expanding as long as it keeps returning a macro. This is so you can use (mutually) recursive macros as a pattern class. invokeOnce only invokes the provided macro the one time and uses that result.

Identity rules

The above example for matching function syntax is a bit verbose because you have to repeat yourself. That's what identity rules are for: they spit out exactly what was matched on. You do this by using ... instead of a normal body for your rule.

macro func {
  rule { function ($args (,) ...) { $body ... } } => ...
  rule { function $name:ident ($args (,) ...) { $body ... } } => ...
}

macro checkFunc {
  rule { $f:invoke(func) } => {
    $f
  }
}

checkFunc function() {} // works
checkFunc 12 // fails

This accounts for wildcards, repeaters with separators, pattern groups, etc so nothing should be dropped. Case macros don't have identity rules, because they would just loop forever!

throwSyntaxCaseError

This is a bit like throwSyntaxError, but should be used specifically when you are using another macro as a pattern class. Internally, sweet.js throws a SyntaxCaseError when a macro fails to match. This just lets you do it manually. Here's how you might use it in a macro that checks for keyword:

macro keyword {
  case { _ $kw } => {
    var kw = #{ $kw };
    if (kw[0].token.type === parser.Token.Keyword) {
      return kw;
    }
    throwSyntaxCaseError('Not a keyword');
  }
}

throwSyntaxError takes an optional message. The message isn't used anywhere currently, but may be used at some point to provide better errors.

Assignee
Assign to
Reviewers
Request review from
Time tracking
Source branch: github/fork/natefaubion/pattern-macros-2