Skip to content

Writing a Code Generator

Firas Dib edited this page Jun 25, 2017 · 4 revisions

Writing a code generator

Your code generator file is just a simple react component. An example can be found below.

Please note that your code generator must handle all the possible cases:

  1. Non-global match
  2. Global match
  3. Non-global substitution
  4. Global substitution
  5. x-mode (this is when a regex can span multiple lines)

You can experiment with the existing flavors to ensure that yours fulfills all cases.

There are a few helper utils you can use:

  • escapeString: Takes a string and any arbitrary amount of characters and escapes them in the subject string. Example: escapeString('foo "bar" baz', '"', 'a') -> foo \"b\ar\" b\az;

Note

The code doesn't have to be perfect, I'd be happy to help you as long as you can get it started yourself.

Template

class MyNewLanguage extends PureComponent {

  //
  // Proptypes

  static propTypes = {
    regex: PropTypes.string.isRequired,
    flags: PropTypes.string.isRequired,
    delimiter: PropTypes.string.isRequired,
    testString: PropTypes.string.isRequired,
    isSubstituting: PropTypes.bool.isRequired,
    isGlobal: PropTypes.bool.isRequired,
    substString: PropTypes.string
  };

  //
  // Control

  // If you need to manipulate any data, you should preferably do it in a function defined 
  // on the class body here. This could for example be sanitizing data (escaping quotes, etc).

  //
  // Render functions

  render() {
    return (
      <Highlight lang="myNewLanguage">
        {this._renderCode()}
      </Highlight>
    );
  }

  _renderCode() {
    const { regex, flags, delimiter, testString, isSubstituting, substString, isGlobal } = this.props;

    const codeString = new CodeString();
  
    // CodeString is a basic class that allows you to create a code snippet without having
    // to worry about indentation or newlines.

    // The only functions are `append`, `indent` and `toString`.
    // The implementation can be found on this page.

    // Create your code string here
    codeString.append(`Use string literals when ${regex} interpolating ${flags} data`);
    
    return codeString.toString();
  }

}

export default MyNewLangauge;

CodeString class

class CodeString {

  constructor(string = '') {
    this.string = string;
    this.indentLevel = 0;
  }

  indent(str, space = 0) {
    return ' '.repeat(space) + str;
  }

  append(str = '', indentLevel) {
    this.string += this.indent(`${str}\n`, this.indentLevel);

    // If `indentLevel` is defined, it will be set until changed later.
    if (indentLevel != null) {
      this.indentLevel = indentLevel;
    }
  }

  toString() {
    return this.string;
  }

}

export default CodeString;

Full example: PHP

class PHP extends PureComponent {

  //
  // Proptypes

  static propTypes = {
    regex: PropTypes.string.isRequired,
    flags: PropTypes.string.isRequired,
    delimiter: PropTypes.string.isRequired,
    testString: PropTypes.string.isRequired,
    isSubstituting: PropTypes.bool.isRequired,
    isGlobal: PropTypes.bool.isRequired,
    substString: PropTypes.string
  };

  //
  // Control

  _escapePHPRegex(regex, delimiter) {
    let escapedRegex = '';

    for (let i = 0, len = regex.length; i < len; i++) {
      switch (regex.charAt(i)) {
        case '\\':
          if (regex.charAt(i + 1) === '\\') {
            escapedRegex += '\\\\\\\\';
          } else {
            escapedRegex += '\\' + regex.charAt(i + 1);
          }
          i++;
          break;
        case '\'':
          escapedRegex += '\\\'';
          break;
        default:
          escapedRegex += regex.charAt(i);
      }
    }

    return escapedRegex;
  }

  //
  // Render functions

  render() {
    return (
      <Highlight lang="php">
        {this._renderCode()}
      </Highlight>
    );
  }

  _renderCode() {
    const { regex, flags, delimiter, testString, isSubstituting, substString, isGlobal } = this.props;

    const codeString = new CodeString();
    const subflags = flags.replace('g', '');

    codeString.append(`$re = '${delimiter}${this._escapePHPRegex(regex)}${delimiter}${subflags}';`);
    codeString.append(`$str = '${escapeString(testString, '\'', '\\')}';`);

    if (isSubstituting) {
      codeString.append(`$subst = '${escapeString(substString, '\'', '\\')}';`);
      codeString.append('');
      codeString.append('$result = preg_replace($re, $subst, $str' + (!isGlobal ? ', 1' : '') + ');');
      codeString.append('');
      codeString.append('echo "The result of the substitution is ".$result;');
    } else {
      codeString.append('');
      if (isGlobal) {
        codeString.append('preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);');
      } else {
        codeString.append('preg_match($re, $str, $matches, PREG_OFFSET_CAPTURE, 0);');
      }
      codeString.append('');
      codeString.append('// Print the entire match result');
      codeString.append('var_dump($matches);');
    }

    return codeString.toString();
  }

}

export default PHP;
Clone this wiki locally