]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Add experimental support for regular expression literals
authorJukka-Pekka Iivonen <jp0409@jippii.fi>
Wed, 24 Mar 2010 09:07:32 +0000 (10:07 +0100)
committerJürg Billeter <j@bitron.ch>
Thu, 25 Mar 2010 09:33:25 +0000 (10:33 +0100)
Fixes bug 607702.

12 files changed:
codegen/valaccodebasemodule.vala
codegen/valaccodegenerator.vala
codegen/valaccodemodule.vala
tests/Makefile.am
tests/objects/regex.vala [new file with mode: 0644]
vala/Makefile.am
vala/valacodevisitor.vala
vala/valaparser.vala
vala/valaregexliteral.vala [new file with mode: 0644]
vala/valascanner.vala
vala/valasemanticanalyzer.vala
vala/valatokentype.vala

index 1e7175d42d143082fc78ea7504f3cdc9448eb929..f839654adfb23633f611332ed02843b675720f65 100644 (file)
@@ -150,6 +150,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
        Set<string> reserved_identifiers;
        
        public int next_temp_var_id = 0;
+       public int next_regex_id = 0;
        public bool in_creation_method { get { return current_method is CreationMethod; } }
        public bool in_constructor = false;
        public bool in_static_or_class_context = false;
@@ -178,6 +179,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
        public DataType int64_type;
        public DataType uint64_type;
        public DataType string_type;
+       public DataType regex_type;
        public DataType float_type;
        public DataType double_type;
        public TypeSymbol gtype_type;
@@ -313,6 +315,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
                float_type = new FloatingType ((Struct) root_symbol.scope.lookup ("float"));
                double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
                string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
+               regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));
 
                var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
                if (unichar_struct != null) {
@@ -3548,6 +3551,42 @@ internal class Vala.CCodeBaseModule : CCodeModule {
                expr.ccodenode = new CCodeConstant.string (expr.value);
        }
 
+       public override void visit_regex_literal (RegexLiteral expr) {
+               string[] parts = expr.value.split ("/", 3);
+               string re = parts[2].escape ("");
+               string flags = "0";
+
+               if (parts[1].contains ("i")) {
+                       flags += " | G_REGEX_CASELESS";
+               }
+               if (parts[1].contains ("m")) {
+                       flags += " | G_REGEX_MULTILINE";
+               }
+               if (parts[1].contains ("s")) {
+                       flags += " | G_REGEX_DOTALL";
+               }
+               if (parts[1].contains ("x")) {
+                       flags += " | G_REGEX_EXTENDED";
+               }
+
+               var regex_var = get_temp_variable (regex_type, true, expr, false);
+               expr.temp_vars.add (regex_var);
+
+               var cdecl = new CCodeDeclaration ("GRegex*");
+
+               var cname = regex_var.name + "regex_" + next_regex_id.to_string ();
+               this.next_regex_id++;
+
+               cdecl.add_declarator (new CCodeVariableDeclarator (cname + " = NULL"));
+               cdecl.modifiers = CCodeModifiers.STATIC;
+
+               var regex_const = new CCodeConstant ("(%s == NULL) ? (%s = g_regex_new (\"".printf (cname, cname)
+                       + re + "\", " + flags + ", 0, NULL)) : %s".printf (cname));
+
+               source_declarations.add_constant_declaration (cdecl);
+               expr.ccodenode = regex_const;
+       }
+
        public override void visit_null_literal (NullLiteral expr) {
                if (context.profile != Profile.GOBJECT) {
                        source_declarations.add_include ("stddef.h");
index f8af697d09fb26e7284f834d67c55112d8236d6c..e7472c263ae835fd5c4ca7bb91bafda2f95788a0 100644 (file)
@@ -280,6 +280,11 @@ public class Vala.CCodeGenerator : CodeGenerator {
                head.visit_tuple (expr);
        }
 
+       public override void visit_regex_literal (RegexLiteral expr) {
+               head.visit_regex_literal (expr);
+       }
+
+
        public override void visit_null_literal (NullLiteral expr) {
                head.visit_null_literal (expr);
        }
index 523ac083d9786b5e20f38766c7d961e685fa1647..1afeac224708547438c3d64a64d0b8312b77d22d 100644 (file)
@@ -259,6 +259,10 @@ public abstract class Vala.CCodeModule {
                next.visit_tuple (expr);
        }
 
+       public virtual void visit_regex_literal (RegexLiteral re) {
+               next.visit_regex_literal (re);
+       }
+
        public virtual void visit_null_literal (NullLiteral expr) {
                next.visit_null_literal (expr);
        }
index 04e3980a84a8a7da85388bd6f5fd937ac4799fe0..929be7a3d1fd2ee41d7bc487700f4fcae4a15c6b 100644 (file)
@@ -55,6 +55,7 @@ TESTS = \
        objects/interfaces.vala \
        objects/methods.vala \
        objects/properties.vala \
+       objects/regex.vala \
        objects/signals.vala \
        objects/test-025.vala \
        objects/test-026.vala \
diff --git a/tests/objects/regex.vala b/tests/objects/regex.vala
new file mode 100644 (file)
index 0000000..1c517f3
--- /dev/null
@@ -0,0 +1,107 @@
+using GLib;
+
+
+static Regex get_from_array (int index)
+{
+       Regex[] arr = {
+               /(\d+\.\d+\.\d+)/,
+               /(\d+)\.\d+\.\d+/,
+               /\d+\.(\d+)\.\d+/,
+               /(\d+)\.\d+\.(\d+)/
+       };
+
+       assert (0 <= index <= 3);
+       return arr[index];
+}
+
+static Regex get_fixed ()
+{
+       return /(is.*ip)/;
+}
+
+class Test : Object {
+       public signal void regexTest (string str);
+       public void run (string s)
+       {
+               regexTest (s);
+       }
+}
+
+void main ()
+{
+       MatchInfo info;
+
+       // Simple greedy regular expression matching, regex received as a function return value.
+       var str1 = "mississippi";
+       if (get_fixed ().match (str1, 0, out info)) {
+               stdout.printf ("Part of %s is '%s'...\n", str1, info.fetch (1));
+       } else {
+               stdout.printf ("Did not match at all.\n");
+       }
+
+       // Match caseless.
+       var str2 = "demonStration";
+       if (/mon(str.*o)n/i.match (str2, 0, out info)) {
+               stdout.printf ("Part of %s is '%s'...\n", str2, info.fetch (1));
+       } else {
+               stdout.printf ("%s did not match at all.\n", str2);
+       }
+
+       // Match and pick substrings.
+       var ts   = "Time: 10:42:12";
+       if (/Time: (..):(..):(..)/.match (ts, 0, out info)) {
+               stdout.printf ("%s\n\thours = %s\n\tminutes = %s\n\tseconds = %s\n\n", ts, info.fetch (1), info.fetch (2), info.fetch (3));
+       }
+
+       // Replace demo: word swapping
+       try {
+               var str = "apple grape";
+               stdout.printf ("'%s' becomes '%s'\n", str, /^([^ ]*) *([^ ]*)/.replace (str, -1, 0, """\2 \1"""));
+       } catch (RegexError err) {
+               // Replacing still needs exception catching
+               message (err.message);
+       }
+
+       // Regex literals in an array
+       for (int i=0; i<4; i++) {
+               if (get_from_array (i).match ("23.3.2010", 0, out info)) {
+                       stdout.printf ("Round %d: %s\n", i, info.fetch (1));
+               }
+       }
+
+       // ??-operator
+       Regex? r = null;
+       Regex? r1 = null;
+       Regex? r2 = null;
+
+       r = r1 ?? r2 ?? /match (this)/i;
+       if (r.match ("match THIS", 0, out info)) {
+               stdout.printf ("Match: %s\n", info.fetch (1));
+       }
+
+       // Escape sequences
+       if (/\.\+\(\)\-\?\/\"\$\[\]\*\^/.match (".+()-?/\"$[]*^")) {
+               stdout.printf ("Matches\n");
+       } else {
+               stdout.printf ("Does not match.\n");
+       }
+
+       // Lambda and closure test
+       Regex? rc = /foo(bar)/i;
+       var test = new Test ();
+       test.regexTest.connect ((s) => {
+               if (rc.match (s, 0, out info)) {
+                       stdout.printf ("Lambda (closure var.): %s -> %s\n", s, info.fetch (1));
+               } else {
+                       stdout.printf ("Does not match.\n");
+               }
+               if (/foo(bar)/i.match (s, 0, out info)) {
+                       stdout.printf ("Lambda (lit.): %s -> %s\n", s, info.fetch (1));
+               } else {
+                       stdout.printf ("Does not match.\n");
+               }
+       });
+       test.run ("fooBar");
+       test.run ("foobAr");
+}
+
index aa0b861f4867c246426b3f95f223ef7a3788867b..f6203a919f541ddb6ec5351d7c7576e0afb5f920 100644 (file)
@@ -118,6 +118,7 @@ libvalacore_la_VALASOURCES = \
        valarealliteral.vala \
        valareferencetransferexpression.vala \
        valareferencetype.vala \
+       valaregexliteral.vala \
        valareport.vala \
        valareturnstatement.vala \
        valascanner.vala \
index 55f87d7cc4f3761c0117cbf697cf82aae9293d8a..5f6a0c8c2fb6667412d4000696c2d22f26c97446 100644 (file)
@@ -468,6 +468,15 @@ public abstract class Vala.CodeVisitor {
        public virtual void visit_real_literal (RealLiteral lit) {
        }
 
+       /**
+        * Visit operation called for regex literals.
+        *
+        * @param lit a regex literal
+        */
+       public virtual void visit_regex_literal (RegexLiteral lit) {
+       }
+
+
        /**
         * Visit operation called for string literals.
         *
index c9563c0acd712af324aacf1e014b3e849f00bd62..15ae81b96983bd15dc847a9924ef266abfb9886c 100644 (file)
@@ -290,6 +290,13 @@ public class Vala.Parser : CodeVisitor {
                                Report.error (lit.source_reference, "invalid character literal");
                        }
                        return lit;
+               case TokenType.REGEX_LITERAL:
+                       next ();
+                       string match_part = get_last_string ();
+                       SourceReference src_begin = get_src (begin);
+                       expect (TokenType.CLOSE_REGEX_LITERAL);
+                       string close_token = get_last_string ();
+                       return new RegexLiteral ("%s/%s".printf (close_token, match_part), src_begin);
                case TokenType.STRING_LITERAL:
                        next ();
                        return new StringLiteral (get_last_string (), get_src (begin));
@@ -560,6 +567,7 @@ public class Vala.Parser : CodeVisitor {
                case TokenType.REAL_LITERAL:
                case TokenType.CHARACTER_LITERAL:
                case TokenType.STRING_LITERAL:
+               case TokenType.REGEX_LITERAL:
                case TokenType.TEMPLATE_STRING_LITERAL:
                case TokenType.VERBATIM_STRING_LITERAL:
                case TokenType.NULL:
@@ -585,6 +593,9 @@ public class Vala.Parser : CodeVisitor {
                case TokenType.OPEN_TEMPLATE:
                        expr = parse_template ();
                        break;
+               case TokenType.OPEN_REGEX_LITERAL:
+                       expr = parse_regex_literal ();
+                       break;
                case TokenType.THIS:
                        expr = parse_this_access ();
                        break;
@@ -694,6 +705,14 @@ public class Vala.Parser : CodeVisitor {
                return template;
        }
 
+       Expression parse_regex_literal () throws ParseError {
+               expect (TokenType.OPEN_REGEX_LITERAL);
+
+               var expr = parse_literal ();
+
+               return expr;
+       }
+
        Expression parse_member_access (SourceLocation begin, Expression inner) throws ParseError {
                expect (TokenType.DOT);
                string id = parse_identifier ();
@@ -985,6 +1004,7 @@ public class Vala.Parser : CodeVisitor {
                                        case TokenType.STRING_LITERAL:
                                        case TokenType.TEMPLATE_STRING_LITERAL:
                                        case TokenType.VERBATIM_STRING_LITERAL:
+                                       case TokenType.REGEX_LITERAL:
                                        case TokenType.NULL:
                                        case TokenType.THIS:
                                        case TokenType.BASE:
diff --git a/vala/valaregexliteral.vala b/vala/valaregexliteral.vala
new file mode 100644 (file)
index 0000000..eb1edd5
--- /dev/null
@@ -0,0 +1,89 @@
+/* valaregexliteral.vala
+ *
+ * Copyright (C) 2010  Jukka-Pekka Iivonen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jukka-Pekka Iivonen <jp0409@jippii.fi>
+ */
+
+using GLib;
+
+/**
+ * Represents a regular expression literal in the source code.
+ */
+public class Vala.RegexLiteral : Literal {
+       /**
+        * The literal value.
+        */
+       public string value { get; set; }
+
+       /**
+        * Creates a new regular expression literal.
+        *
+        * @param s      the literal value
+        * @param source reference to source code
+        * @return       newly created string literal
+        */
+       public RegexLiteral (string value, SourceReference? source_reference = null) {
+               this.value = value;
+               this.source_reference = source_reference;
+       }
+
+       public override void accept (CodeVisitor visitor) {
+               visitor.visit_regex_literal (this);
+
+               visitor.visit_expression (this);
+       }
+
+       public override bool is_pure () {
+               return true;
+       }
+
+       public override bool is_non_null () {
+               return true;
+       }
+
+       public override string to_string () {
+               return value;
+       }
+
+       public override bool check (SemanticAnalyzer analyzer) {
+               if (checked) {
+                       return !error;
+               }
+
+               checked = true;
+
+               if (!analyzer.context.experimental) {
+                       Report.warning (source_reference, "regular expression literals are experimental");
+               }
+
+               try {
+                       var regex = new GLib.Regex (value);
+                       if (regex != null) { /* Regex is valid. */ }
+               } catch (RegexError err) {
+                       error = true;
+                       Report.error (source_reference, "Invalid regular expression `%s'.".printf (value));
+                       return false;
+               }
+
+               value_type = analyzer.regex_type.copy ();
+
+               return !error;
+       }
+}
+
index 744dcf14c8ccb37fe6362d298939425ede63cab6..3a05b5c3710140e91f6ed8f359343e31f5e30c5e 100644 (file)
@@ -18,6 +18,7 @@
  *
  * Author:
  *     Jürg Billeter <j@bitron.ch>
+ *     Jukka-Pekka Iivonen <jp0409@jippii.fi>
  */
 
 using GLib;
@@ -28,6 +29,7 @@ using GLib;
 public class Vala.Scanner {
        public SourceFile source_file { get; private set; }
 
+       TokenType previous;
        char* current;
        char* end;
 
@@ -51,7 +53,8 @@ public class Vala.Scanner {
                BRACE,
                BRACKET,
                TEMPLATE,
-               TEMPLATE_PART
+               TEMPLATE_PART,
+               REGEX_LITERAL
        }
 
        public Scanner (SourceFile source_file) {
@@ -83,10 +86,178 @@ public class Vala.Scanner {
                return (state_stack.length > 0 && state_stack[state_stack.length - 1] == State.TEMPLATE_PART);
        }
 
+       bool in_regex_literal () {
+               return (state_stack.length > 0 && state_stack[state_stack.length - 1] == State.REGEX_LITERAL);
+       }
+
        bool is_ident_char (char c) {
                return (c.isalnum () || c == '_');
        }
 
+       public TokenType read_regex_token (out SourceLocation token_begin, out SourceLocation token_end) {
+               TokenType type;
+               char* begin = current;
+               token_begin.pos = begin;
+               token_begin.line = line;
+               token_begin.column = column;
+
+               int token_length_in_chars = -1;
+
+               if (current >= end) {
+                       type = TokenType.EOF;
+               } else {
+                       switch (current[0]) {
+                       case '/':
+                               type = TokenType.CLOSE_REGEX_LITERAL;
+                               current++;
+                               state_stack.length--;
+                               var fl_i = false;
+                               var fl_s = false;
+                               var fl_m = false;
+                               var fl_x = false;
+                               while (current[0] == 'i' || current[0] == 's' || current[0] == 'm' || current[0] == 'x') {
+                                       switch (current[0]) {
+                                       case 'i':
+                                               if (fl_i) {
+                                                       Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "modifier 'i' used more than once");
+                                               }
+                                               fl_i = true;
+                                               break;
+                                       case 's':
+                                               if (fl_s) {
+                                                       Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "modifier 's' used more than once");
+                                               }
+                                               fl_s = true;
+                                               break;
+                                       case 'm':
+                                               if (fl_m) {
+                                                       Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "modifier 'm' used more than once");
+                                               }
+                                               fl_m = true;
+                                               break;
+                                       case 'x':
+                                               if (fl_x) {
+                                                       Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "modifier 'x' used more than once");
+                                               }
+                                               fl_x = true;
+                                               break;
+                                       }
+                                       current++;
+                                       token_length_in_chars++;
+                               }
+                               break;
+                       default:
+                               type = TokenType.REGEX_LITERAL;
+                               token_length_in_chars = 0;
+                               while (current < end && current[0] != '/') {
+                                       if (current[0] == '\\') {
+                                               current++;
+                                               token_length_in_chars++;
+                                               if (current >= end) {
+                                                       break;
+                                               }
+
+                                               switch (current[0]) {
+                                               case '\'':
+                                               case '"':
+                                               case '\\':
+                                               case '/':
+                                               case '^':
+                                               case '$':
+                                               case '.':
+                                               case '[':
+                                               case ']':
+                                               case '{':
+                                               case '}':
+                                               case '(':
+                                               case ')':
+                                               case '?':
+                                               case '*':
+                                               case '+':
+                                               case '-':
+                                               case '#':
+                                               case '&':
+                                               case '~':
+                                               case ':':
+                                               case ';':
+                                               case '<':
+                                               case '>':
+                                               case '|':
+                                               case '%':
+                                               case '=':
+                                               case '@':
+                                               case '0':
+                                               case 'b':
+                                               case 'B':
+                                               case 'f':
+                                               case 'n':
+                                               case 'r':
+                                               case 't':
+                                               case 'a':
+                                               case 'A':
+                                               case 'p':
+                                               case 'P':
+                                               case 'e':
+                                               case 'd':
+                                               case 'D':
+                                               case 's':
+                                               case 'S':
+                                               case 'w':
+                                               case 'W':
+                                               case 'G':
+                                               case 'z':
+                                               case 'Z':
+                                                       current++;
+                                                       token_length_in_chars++;
+                                                       break;
+                                               case 'x':
+                                                       // hexadecimal escape character
+                                                       current++;
+                                                       token_length_in_chars++;
+                                                       while (current < end && current[0].isxdigit ()) {
+                                                               current++;
+                                                               token_length_in_chars++;
+                                                       }
+                                                       break;
+                                               default:
+                                                       Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "invalid escape sequence");
+                                                       break;
+                                               }
+                                       } else if (current[0] == '\n') {
+                                               break;
+                                       } else {
+                                               unichar u = ((string) current).get_char_validated ((long) (end - current));
+                                               if (u != (unichar) (-1)) {
+                                                       current += u.to_utf8 (null);
+                                                       token_length_in_chars++;
+                                               } else {
+                                                       current++;
+                                                       Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "invalid UTF-8 character");
+                                               }
+                                       }
+                               }
+                               if (current >= end || current[0] == '\n') {
+                                       Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "syntax error, expected \"");
+                                       state_stack.length--;
+                                       return read_token (out token_begin, out token_end);
+                               }
+                               break;
+                       }
+               }
+
+               if (token_length_in_chars < 0) {
+                       column += (int) (current - begin);
+               } else {
+                       column += token_length_in_chars;
+               }
+
+               token_end.pos = current;
+               token_end.line = line;
+               token_end.column = column - 1;
+
+               return type;
+       }
+
        public static TokenType get_identifier_or_keyword (char* begin, int len) {
                switch (len) {
                case 2:
@@ -585,6 +756,8 @@ public class Vala.Scanner {
                        token_end.column = column - 1;
 
                        return TokenType.COMMA;
+               } else if (in_regex_literal ()) {
+                       return read_regex_token (out token_begin, out token_end);
                }
 
                space ();
@@ -843,11 +1016,18 @@ public class Vala.Scanner {
                                }
                                break;
                        case '/':
-                               type = TokenType.DIV;
-                               current++;
-                               if (current < end && current[0] == '=') {
-                                       type = TokenType.ASSIGN_DIV;
+                               if (previous == TokenType.OPEN_PARENS || previous == TokenType.ASSIGN || previous == TokenType.OP_COALESCING
+                                   || previous == TokenType.COMMA || previous == TokenType.RETURN || previous == TokenType.OPEN_BRACE) {
+                                       type = TokenType.OPEN_REGEX_LITERAL;
+                                       state_stack += State.REGEX_LITERAL;
+                                       current++;
+                               } else {
+                                       type = TokenType.DIV;
                                        current++;
+                                       if (current < end && current[0] == '=') {
+                                               type = TokenType.ASSIGN_DIV;
+                                               current++;
+                                       }
                                }
                                break;
                        case '%':
@@ -979,6 +1159,7 @@ public class Vala.Scanner {
                token_end.pos = current;
                token_end.line = line;
                token_end.column = column - 1;
+               previous = type;
 
                return type;
        }
index 818ea7d5047878e56fde51362c937946d6875725..54e6ced911b72cfcbbf71d582b3cfca5bdca2cd8 100644 (file)
@@ -132,6 +132,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
        public DataType void_type = new VoidType ();
        public DataType bool_type;
        public DataType string_type;
+       public DataType regex_type;
        public DataType uchar_type;
        public DataType short_type;
        public DataType ushort_type;
@@ -176,6 +177,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 
                bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
                string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
+               regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));
 
                short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
                ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
index 88b876708b9378a94ca6948828bfb485369a8ea4..8a246841f79cf9c4c6ea6c61d2433fd5c58bbfd7 100644 (file)
@@ -49,6 +49,7 @@ public enum Vala.TokenType {
        CLOSE_BRACE,
        CLOSE_BRACKET,
        CLOSE_PARENS,
+       CLOSE_REGEX_LITERAL,
        CLOSE_TEMPLATE,
        COLON,
        COMMA,
@@ -109,6 +110,7 @@ public enum Vala.TokenType {
        OPEN_BRACE,
        OPEN_BRACKET,
        OPEN_PARENS,
+       OPEN_REGEX_LITERAL,
        OPEN_TEMPLATE,
        OVERRIDE,
        OWNED,
@@ -120,6 +122,7 @@ public enum Vala.TokenType {
        PUBLIC,
        REAL_LITERAL,
        REF,
+       REGEX_LITERAL,
        REQUIRES,
        RETURN,
        SEMICOLON,
@@ -177,6 +180,7 @@ public enum Vala.TokenType {
                case CLOSE_BRACE: return "`}'";
                case CLOSE_BRACKET: return "`]'";
                case CLOSE_PARENS: return "`)'";
+               case CLOSE_REGEX_LITERAL: return "`/'";
                case COLON: return "`:'";
                case COMMA: return "`,'";
                case CONST: return "`const'";
@@ -232,6 +236,7 @@ public enum Vala.TokenType {
                case OPEN_BRACE: return "`{'";
                case OPEN_BRACKET: return "`['";
                case OPEN_PARENS: return "`('";
+               case OPEN_REGEX_LITERAL: return "`/'";
                case OVERRIDE: return "`override'";
                case OWNED: return "`owned'";
                case PARAMS: return "`params'";
@@ -242,6 +247,7 @@ public enum Vala.TokenType {
                case PUBLIC: return "`public'";
                case REAL_LITERAL: return "real literal";
                case REF: return "`ref'";
+               case REGEX_LITERAL: return "regex literal";
                case REQUIRES: return "`requires'";
                case RETURN: return "`return'";
                case SEMICOLON: return "`;'";