Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wren Support #2875

Closed
clsource opened this issue Apr 24, 2021 · 11 comments · Fixed by #3063
Closed

Wren Support #2875

clsource opened this issue Apr 24, 2021 · 11 comments · Fixed by #3063

Comments

@clsource
Copy link

Wren Language

Wren is a small, fast, class-based concurrent scripting language

Think Smalltalk in a Lua-sized package with a dash of Erlang and wrapped up in a familiar, modern syntax.

System.print("Hello, world!")

class Wren {
  flyTo(city) {
    System.print("Flying to %(city)")
  }
}

var adjectives = Fiber.new {
  ["small", "clean", "fast"].each {|word| Fiber.yield(word) }
}

while (!adjectives.isDone) System.print(adjectives.call())

Additional resources

Possible Implementation

Butchered some available languages and came with something. But stills needs some testing 👍

// Prism.languages.wren
export default (function (Prism) {
  var multilineComment = /\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|<self>)*\*\//.source;
  for (var i = 0; i < 2; i++) {
    // support 4 levels of nested comments
    multilineComment = multilineComment.replace(/<self>/g, function () { return multilineComment; });
  }
  multilineComment = multilineComment.replace(/<self>/g, function () { return /[^\s\S]/.source; });

  Prism.languages.wren = {
    'hashbang': {
      pattern: /^#!.*/,
      greedy: true,
      alias: 'comment'
    },
    'comment': [
      {
        pattern: RegExp(/(^|[^\\])/.source + multilineComment),
        lookbehind: true,
        greedy: true
      },
      {
        pattern: /(^|[^\\:])\/\/.*/,
        lookbehind: true,
        greedy: true
      }
    ],
    'triple-quoted-string': {
      pattern: /(?:[])?(""")[\s\S]*?\1/i,
      greedy: true,
      alias: 'string'
    },
    'string': {
      pattern: /(?:[])?(")[\s\S]*?\1/i,
      greedy: true
    },
    'class-name': {
      pattern: /(\b(?:class|is|Num|System|Object|Sequence|List|Map|Bool|String|Range|Fn|Fiber)\s+|\bcatch\s+\()[\w.\\]+/i,
      lookbehind: true,
      inside: {
        'punctuation': /[.\\]/
      }
    },
    'keyword': /\b(?:if|else|while|for|return|in|is|as|null|break|continue|foreign|construct|static|var|class|this|super|#!|#)\b/,
    'boolean': /\b(?:true|false)\b/,
    'number': /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
    'null': {
      pattern: /\bnull\b/,
      alias: 'keyword'
    },
    'function': /(?!\d)\w+(?=\s*(?:[({]))/,
    'operator': [
        /[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,
        {
          // Match ".." but don't break "..."
          pattern: /(^|[^.])\.\.(?!\.)/,
          lookbehind: true
        }
      ],
    'punctuation': /[\[\](){},;]|\.+|:+/
  };
});
@nailuj29
Copy link

Wren is great!

@joshgoebel
Copy link

joshgoebel commented Apr 24, 2021

@clsource Any chance you might be willing to work on a grammar for Highlight.js also? Wren is indeed cool, I'm vaguely familiar with it from TIC-80.

@RunDevelopment Do you mind post such questions if they are infrequent? :)

@RunDevelopment
Copy link
Member

@clsource Would you like to do a PR?

@joshgoebel I think it's ok. It's a little off-topic but you also contribute by responding to comments and sharing your experience, so I don't mind.

@clsource
Copy link
Author

clsource commented Apr 25, 2021

Sure when a more polished and tested version is available I will do a PR 👍

@clsource Any chance you might be willing to work on a grammar for Highlight.js also? Wren is indeed cool, I'm vaguely familiar with it from TIC-80.

maybe, for now I will focus on prism 👍

@joshgoebel
Copy link

@clsource It seems wren.io is already using Prism? Did anyone ask to see what grammar they are using? Or is that you?

@clsource
Copy link
Author

The current syntax in wren.io is a modified lua and its not complete. Thats why I made a more tailored implementation

@RunDevelopment
Copy link
Member

@clsource Would it be alright with you if I make a PR based on your language definition?

@nailuj29
Copy link

@RunDevelopment I think they've updated it a bit, they've shared some screenshots in the wren discord

@clsource
Copy link
Author

The current version is this. But still needs a little more testing :)

// Prism.languages.wren
export default (function (Prism) {

  var multilineComment = /\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|<self>)*\*\//.source;
  for (var i = 0; i < 2; i++) {
      // Supports up to 4 levels of nested comments
      multilineComment = multilineComment.replace(/<self>/g, function () { return multilineComment; });
  }
  multilineComment = multilineComment.replace(/<self>/g, function () { return /[^\s\S]/.source; });

  var wren = {
      'comment': [
          {
              pattern: RegExp(/(^|[^\\])/.source + multilineComment),
              lookbehind: true,
              greedy: true
          },
          {
              pattern: /(^|[^\\:])\/\/.*/,
              lookbehind: true,
              greedy: true
          }
      ],
      'triple-quoted-string': {
          pattern: /(?:[])?(""")[\s\S]*?\1/iu,
          greedy: true,
          alias: 'string'
      },
      'string': {
          pattern: /"(?:\\[\s\S]|%\((?:[^()]|\((?:[^()]|\([^)]*\))*\))+\)|(?!%\()[^\\"])*"/u,
          greedy: true,
          inside: {}
          // Interpolation defined at the end of this function
      },
      'boolean': /\b(?:true|false)\b/,
      'number': /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
      'null': {
          pattern: /\bnull\b/,
          alias: 'keyword'
      },
      // Highlight predefined classes and wren_cli classes as builtin
      'builtin': /\b(?:Num|System|Object|Sequence|List|Map|Bool|String|Range|Fn|Fiber|Meta|Random|File|Directory|Stat|Stdin|Stdout|Platform|Process|Scheduler|Timer)\b/,
      'attribute': [
          {
              pattern: /^#.*/,
              greedy: false,
              alias: 'keyword'
          },
          {
              pattern: /^#!.*/,
              greedy: false,
              alias: 'variable'
          },
      ],
      'class-name': [
          {
              // class definition
              // class Meta {}
              pattern: /(\b(?:class)\s+)[\w.\\]+/i,
              lookbehind: true,
              inside: {
                  'punctuation': /[.\\]/
              }
          },
          {
            // A class must always start with an uppercase.
            // File.read
            pattern:/\b[A-Z](?:[_a-z]|\dx?)*\b/,
            lookbehind:true,
            inside: {
              'punctuation': /[.\\]/
            }
          }
      ],
      'constant': /\b[A-Z](?:[A-Z_]|\dx?)*\b/,
      'keyword': /\b(?:if|else|while|for|return|in|is|as|null|break|continue|foreign|construct|static|var|class|this|super|#!|#|import)\b/,
      'function': /(?!\d)\w+(?=\s*(?:[({]))/,
      'operator': [
          /[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,
          {
              // Match ".." but don't break "..."
              pattern: /(^|[^.])\.\.(?!\.)/,
              lookbehind: true
          }
      ],
      'punctuation': /[\[\](){},;]|\.+|:+/,
      'variable': /[a-zA-Z_]\w*(?:[?!]|\b)/,
  };

  var stringInside = {
    'template-punctuation': {
      pattern: /^"|"$/,
      alias: 'string'
    },
    'interpolation': {
      pattern: /((?:^|[^\\])(?:\\{2})*)%\((?:[^()]|\((?:[^()]|\([^)]*\))*\))+\)/,
      lookbehind: true,
      inside: {
        'interpolation-punctuation': {
          pattern: /^%(|)$/,
          alias: 'punctuation'
        },
        rest: wren
      }
    },
    'string': /[\s\S]+/iu
  };

  // Only single quote strings can have interpolation
  wren['string'].inside = stringInside;

  Prism.languages.wren = wren;
});

@RunDevelopment
Copy link
Member

That looks better! Maybe a few point to improve:

  • triple-quoted-string: The (?:[])? can be removed. The backreference is also unnecessary since it can only match one string.
  • attribute: greedy is false by default. The /^#!.*/ pattern can never be matched because it is a subset of the above /^#.*/ pattern.
  • class-name: the /\b[A-Z](?:[_a-z]|\dx?)*\b/ has an exponential worst case. Use /\b[A-Z][a-z\d_]*\b/ instead (both patterns are equivalent).

@clsource
Copy link
Author

Ok implemented your suggestions and added hashbangs 👍

// https://wren.io/
// Prism.languages.wren
export default (function (Prism) {

  // Multiline based on prism-rust.js
  var multilineComment = /\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|<self>)*\*\//.source;
  for (var i = 0; i < 2; i++) {
      // Supports up to 4 levels of nested comments
      multilineComment = multilineComment.replace(/<self>/g, function () { return multilineComment; });
  }
  multilineComment = multilineComment.replace(/<self>/g, function () { return /[^\s\S]/.source; });

  var wren = {
      // Multiline comments in Wren can have nested multiline comments
      // Comments: // and /* */
      'comment': [
          {
              pattern: RegExp(/(^|[^\\])/.source + multilineComment),
              lookbehind: true,
              greedy: true
          },
          {
              pattern: /(^|[^\\:])\/\/.*/,
              lookbehind: true,
              greedy: true
          }
      ],

      // Triple quoted strings are multiline but cannot have interpolation (raw strings)
      // Based on prism-python.js
      'triple-quoted-string': {
          pattern: /(""")[\s\S]*?\1/iu,
          greedy: true,
          alias: 'string'
      },

      // A single quote string is multiline and can have interpolation (similar to JS backticks ``)
      'string': {
          pattern: /"(?:\\[\s\S]|%\((?:[^()]|\((?:[^()]|\([^)]*\))*\))+\)|(?!%\()[^\\"])*"/u,
          greedy: true,
          inside: {}
          // Interpolation defined at the end of this function
      },

      'boolean': /\b(?:true|false)\b/,
      'number': /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
      'null': {
          pattern: /\bnull\b/,
          alias: 'keyword'
      },

      // Highlight predefined classes and wren_cli classes as builtin
      'builtin': /\b(?:Num|System|Object|Sequence|List|Map|Bool|String|Range|Fn|Fiber|Meta|Random|File|Directory|Stat|Stdin|Stdout|Platform|Process|Scheduler|Timer)\b/,

      // Attributes are special keywords to add meta data to classes
      'attribute': [
          // #! attributes are stored in class properties
          // #!myvar = true
          // #attributes are not stored and dismissed at compilation
          {
              pattern: /#!?[ \t\u3000]*[A-Za-z_\d]+\b/u,
              alias: 'keyword'
          },
      ],
      // #!/usr/bin/env wren on the first line
      'hashbang': [
        {
          pattern: /#!\/[\S \t\u3000]+/u,
          greedy:true,
          alias:'constant'
        }
      ],
      'class-name': [
          {
              // class definition
              // class Meta {}
              pattern: /(\b(?:class)\s+)[\w.\\]+/i,
              lookbehind: true,
              inside: {
                  'punctuation': /[.\\]/
              }
          },
          {
            // A class must always start with an uppercase.
            // File.read
            pattern: /\b[A-Z][a-z\d_]*\b/,
            lookbehind:true,
            inside: {
              'punctuation': /[.\\]/
            }
          }
      ],

      // A constant can be a variable, class, property or method. Just named in all uppercase letters
      'constant': /\b[A-Z][A-Z\d_]*\b/,

      'keyword': /\b(?:if|else|while|for|return|in|is|as|null|break|continue|foreign|construct|static|var|class|this|super|#!|#|import)\b/,

      // Functions can be Class.method()
      'function': /(?!\d)\w+(?=\s*(?:[({]))/,

      // Traditional operators but adding .. and ... for Ranges e.g.: 1..2
      // Based on prism-lua.js
      'operator': [
          /[-+*%^&|]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,
          {
              // Match ".." but don't break "..."
              pattern: /(^|[^.])\.\.(?!\.)/,
              lookbehind: true
          }
      ],
      // Traditional punctuation although ; is not used in Wren
      'punctuation': /[\[\](){},;]|\.+|:+/,
      'variable': /[a-zA-Z_\d]\w*\b/,
  };

  // Based on prism-javascript.js interpolation
  // "%(interpolation)"
  var stringInside = {
    'template-punctuation': {
      pattern: /^"|"$/,
      alias: 'string'
    },
    'interpolation': {
      pattern: /((?:^|[^\\])(?:\\{2})*)%\((?:[^()]|\((?:[^()]|\([^)]*\))*\))+\)/,
      lookbehind: true,
      inside: {
        'interpolation-punctuation': {
          pattern: /^%(|)$/,
          alias: 'punctuation'
        },
        rest: wren
      }
    },
    'string': /[\s\S]+/iu
  };

  // Only single quote strings can have interpolation
  wren['string'].inside = stringInside;

  Prism.languages.wren = wren;
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants