]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
vala: Add support for verbatim template string
author星外之神 <wszqkzqk@qq.com>
Fri, 28 Oct 2022 15:47:56 +0000 (23:47 +0800)
committerRico Tzschichholz <ricotz@ubuntu.com>
Sun, 30 Oct 2022 15:11:11 +0000 (16:11 +0100)
Fixes https://gitlab.gnome.org/GNOME/vala/issues/1373

19 files changed:
tests/Makefile.am
tests/genie/literal-template-string.c-expected
tests/genie/literal-template-string.gs
tests/genie/verbatim-template.c-expected [new file with mode: 0644]
tests/genie/verbatim-template.gs [new file with mode: 0644]
tests/parser/template.c-expected
tests/parser/template.vala
tests/parser/verbatim-template.c-expected [new file with mode: 0644]
tests/parser/verbatim-template.vala [new file with mode: 0644]
tests/scanner/string-template.c-expected [new file with mode: 0644]
tests/scanner/string-template.vala [new file with mode: 0644]
tests/scanner/string-verbatim-template.c-expected [new file with mode: 0644]
tests/scanner/string-verbatim-template.vala [new file with mode: 0644]
vala/valagenieparser.vala
vala/valageniescanner.vala
vala/valagenietokentype.vala
vala/valaparser.vala
vala/valascanner.vala
vala/valatokentype.vala

index 10ff6183ff43b3e671e87ee975625ba1372b21a3..b93d4963caee98bb2b150b280c25bbd2702fc95d 100644 (file)
@@ -908,6 +908,8 @@ TESTS = \
        scanner/string-escape-x-digit-length.test \
        scanner/string-escape-x-empty.test \
        scanner/string-escape-x.vala \
+       scanner/string-template.vala \
+       scanner/string-verbatim-template.vala \
        parser/argument-list-incomplete.test \
        parser/array-creation-invalid.test \
        parser/array-length.vala \
@@ -1006,6 +1008,7 @@ TESTS = \
        parser/using-invalid-namespace.test \
        parser/var-type-dynamic.vala \
        parser/var-type-nullable.vala \
+       parser/verbatim-template.vala \
        parser/with-embedded.vala \
        parser/with-empty.vala \
        parser/with-invalid-declaration.test \
@@ -1403,6 +1406,7 @@ TESTS = \
        genie/struct-after-class.gs \
        genie/try-except-finally.gs \
        genie/typeof.gs \
+       genie/verbatim-template.gs \
        genie/while.gs \
        glib/conditional-glib-api.vala \
        bindings/gio/memoryoutputstream.vala \
index 9dad5e43200035035413ecec07508dc1df333ed0..0333b854611ca6c35f70ab6bd0a8994aa726a09b 100644 (file)
@@ -5,15 +5,36 @@
 #include <string.h>
 #include <glib.h>
 
+#if !defined(VALA_EXTERN)
+#if defined(_MSC_VER)
+#define VALA_EXTERN __declspec(dllexport) extern
+#elif __GNUC__ >= 4
+#define VALA_EXTERN __attribute__((visibility("default"))) extern
+#else
+#define VALA_EXTERN extern
+#endif
+#endif
+
 #define _g_free0(var) (var = (g_free (var), NULL))
 #define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
 #define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }
 #define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
 #define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
 
+VALA_EXTERN gchar* m (void);
 static void _vala_main (gchar** args,
                  gint args_length1);
 
+gchar*
+m (void)
+{
+       gchar* _tmp0_;
+       gchar* result;
+       _tmp0_ = g_strdup ("foo");
+       result = _tmp0_;
+       return result;
+}
+
 static const gchar*
 string_to_string (const gchar* self)
 {
@@ -27,28 +48,35 @@ static void
 _vala_main (gchar** args,
             gint args_length1)
 {
-       gchar* a = NULL;
+       gchar* _result_ = NULL;
        gchar* _tmp0_;
-       gint b = 0;
-       gchar* c = NULL;
        const gchar* _tmp1_;
+       gint i = 0;
        gchar* _tmp2_;
        gchar* _tmp3_;
        gchar* _tmp4_;
        gchar* _tmp5_;
-       _tmp0_ = g_strdup ("test");
-       a = _tmp0_;
-       b = 100;
-       _tmp1_ = string_to_string (a);
-       _tmp2_ = g_strdup_printf ("%i", b);
+       const gchar* _tmp6_;
+       gchar* _tmp7_;
+       const gchar* _tmp8_;
+       _tmp0_ = g_strdup ("");
+       _result_ = _tmp0_;
+       _tmp1_ = _result_;
+       _vala_assert (g_strcmp0 (_tmp1_, "") == 0, "result == \"\"");
+       i = 42;
+       _tmp2_ = g_strdup_printf ("%i", i);
        _tmp3_ = _tmp2_;
-       _tmp4_ = g_strconcat (_tmp1_, _tmp3_, NULL);
+       _tmp4_ = m ();
        _tmp5_ = _tmp4_;
+       _tmp6_ = string_to_string (_tmp5_);
+       _tmp7_ = g_strconcat ("i=", _tmp3_, " m=", _tmp6_, " ", "$", NULL);
+       _g_free0 (_result_);
+       _result_ = _tmp7_;
+       _g_free0 (_tmp5_);
        _g_free0 (_tmp3_);
-       c = _tmp5_;
-       _vala_assert (g_strcmp0 (c, "test100") == 0, "c == \"test100\"");
-       _g_free0 (c);
-       _g_free0 (a);
+       _tmp8_ = _result_;
+       _vala_assert (g_strcmp0 (_tmp8_, "i=42 m=foo $") == 0, "result == \"i=42 m=foo $\"");
+       _g_free0 (_result_);
 }
 
 int
index 87e75ae920e3e54f3923ba43a57057bc9a702770..8c7dc617d7fb9ede92c6ce885da4139932c2a6b3 100644 (file)
@@ -1,5 +1,10 @@
+def m():string
+       return "foo"
+
 init
-       var a = "test"
-       var b = 100
-       var c = @"$( a )$b"
-       assert( c == "test100" )
+       result:string = @""
+       assert( result == "" )
+
+       i:int = 42
+       result = @"i=$i m=$( m() ) $$"
+       assert( result == "i=42 m=foo $" )
diff --git a/tests/genie/verbatim-template.c-expected b/tests/genie/verbatim-template.c-expected
new file mode 100644 (file)
index 0000000..97531c0
--- /dev/null
@@ -0,0 +1,103 @@
+/* genie_verbatim_template.c generated by valac, the Vala compiler
+ * generated from genie_verbatim_template.gs, do not modify */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#if !defined(VALA_EXTERN)
+#if defined(_MSC_VER)
+#define VALA_EXTERN __declspec(dllexport) extern
+#elif __GNUC__ >= 4
+#define VALA_EXTERN __attribute__((visibility("default"))) extern
+#else
+#define VALA_EXTERN extern
+#endif
+#endif
+
+#define _g_free0(var) (var = (g_free (var), NULL))
+#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }
+#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
+#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+
+VALA_EXTERN gchar* m (void);
+static void _vala_main (gchar** args,
+                 gint args_length1);
+
+gchar*
+m (void)
+{
+       gchar* _tmp0_;
+       gchar* result;
+       _tmp0_ = g_strdup ("foo");
+       result = _tmp0_;
+       return result;
+}
+
+static const gchar*
+string_to_string (const gchar* self)
+{
+       const gchar* result;
+       g_return_val_if_fail (self != NULL, NULL);
+       result = self;
+       return result;
+}
+
+static void
+_vala_main (gchar** args,
+            gint args_length1)
+{
+       gchar* _result_ = NULL;
+       gchar* _tmp0_;
+       const gchar* _tmp1_;
+       gint i = 0;
+       gchar* _tmp2_;
+       gchar* _tmp3_;
+       gchar* _tmp4_;
+       gchar* _tmp5_;
+       const gchar* _tmp6_;
+       gchar* _tmp7_;
+       const gchar* _tmp8_;
+       gint a = 0;
+       gchar* _tmp9_;
+       gchar* _tmp10_;
+       gchar* _tmp11_;
+       const gchar* _tmp12_;
+       _tmp0_ = g_strdup ("");
+       _result_ = _tmp0_;
+       _tmp1_ = _result_;
+       _vala_assert (g_strcmp0 (_tmp1_, "") == 0, "result == \"\"");
+       i = 42;
+       _tmp2_ = g_strdup_printf ("%i", i);
+       _tmp3_ = _tmp2_;
+       _tmp4_ = m ();
+       _tmp5_ = _tmp4_;
+       _tmp6_ = string_to_string (_tmp5_);
+       _tmp7_ = g_strconcat ("i=", _tmp3_, " \nm=", _tmp6_, " \n", "$", NULL);
+       _g_free0 (_result_);
+       _result_ = _tmp7_;
+       _g_free0 (_tmp5_);
+       _g_free0 (_tmp3_);
+       _tmp8_ = _result_;
+       _vala_assert (g_strcmp0 (_tmp8_, "i=42 \nm=foo \n$") == 0, "result == \"i=42 \\nm=foo \\n$\"");
+       a = 4711;
+       _tmp9_ = g_strdup_printf ("%i", a);
+       _tmp10_ = _tmp9_;
+       _tmp11_ = g_strconcat ("\"", _tmp10_, "\"", "\"", NULL);
+       _g_free0 (_result_);
+       _result_ = _tmp11_;
+       _g_free0 (_tmp10_);
+       _tmp12_ = _result_;
+       _vala_assert (g_strcmp0 (_tmp12_, "\"4711\"\"") == 0, "result == \"\\\"4711\\\"\\\"\"");
+       _g_free0 (_result_);
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main (argv, argc);
+       return 0;
+}
+
diff --git a/tests/genie/verbatim-template.gs b/tests/genie/verbatim-template.gs
new file mode 100644 (file)
index 0000000..92f9a5c
--- /dev/null
@@ -0,0 +1,16 @@
+def m():string
+       return "foo"
+
+init
+       result:string = @""""""
+       assert( result == "" )
+
+       i:int = 42
+       result = @"""i=$i 
+m=$( m() ) 
+$$"""
+       assert( result == "i=42 \nm=foo \n$" )
+
+       a:int = 4711
+       result = @""""$a"""""
+       assert( result == "\"4711\"\"" )
index 933aa14f54cbd1ab49148171caaae4fafec18d02..093acfe15245f9441419b670845d9a12c4b4c9d5 100644 (file)
@@ -46,27 +46,30 @@ _vala_main (void)
 {
        gchar* _result_ = NULL;
        gchar* _tmp0_;
+       const gchar* _tmp1_;
        gint i = 0;
-       gchar* _tmp1_;
        gchar* _tmp2_;
-       const gchar* _tmp3_;
+       gchar* _tmp3_;
        const gchar* _tmp4_;
-       gchar* _tmp5_;
-       const gchar* _tmp6_;
+       const gchar* _tmp5_;
+       gchar* _tmp6_;
+       const gchar* _tmp7_;
        _tmp0_ = g_strdup ("");
        _g_free0 (_result_);
        _result_ = _tmp0_;
+       _tmp1_ = _result_;
+       _vala_assert (g_strcmp0 (_tmp1_, "") == 0, "result == \"\"");
        i = 42;
-       _tmp1_ = g_strdup_printf ("%i", i);
-       _tmp2_ = _tmp1_;
-       _tmp3_ = m ();
-       _tmp4_ = string_to_string (_tmp3_);
-       _tmp5_ = g_strconcat ("i=", _tmp2_, " m=", _tmp4_, " ", "$", NULL);
+       _tmp2_ = g_strdup_printf ("%i", i);
+       _tmp3_ = _tmp2_;
+       _tmp4_ = m ();
+       _tmp5_ = string_to_string (_tmp4_);
+       _tmp6_ = g_strconcat ("i=", _tmp3_, " m=", _tmp5_, " ", "$", NULL);
        _g_free0 (_result_);
-       _result_ = _tmp5_;
-       _g_free0 (_tmp2_);
-       _tmp6_ = _result_;
-       _vala_assert (g_strcmp0 (_tmp6_, "i=42 m=foo $") == 0, "result == \"i=42 m=foo $\"");
+       _result_ = _tmp6_;
+       _g_free0 (_tmp3_);
+       _tmp7_ = _result_;
+       _vala_assert (g_strcmp0 (_tmp7_, "i=42 m=foo $") == 0, "result == \"i=42 m=foo $\"");
        _g_free0 (_result_);
 }
 
index b4a073676eda76ee85fee34ea93a1f8dedac75fe..f1fd76cfe85849581952d16fb8f0da59fb81c1cb 100644 (file)
@@ -5,6 +5,7 @@ unowned string m () {
 void main () {
        string result;
        result = @"";
+       assert (result == "");
 
        int i = 42;
        result = @"i=$i m=$(m ()) $$";
diff --git a/tests/parser/verbatim-template.c-expected b/tests/parser/verbatim-template.c-expected
new file mode 100644 (file)
index 0000000..108cae7
--- /dev/null
@@ -0,0 +1,83 @@
+/* parser_verbatim_template.c generated by valac, the Vala compiler
+ * generated from parser_verbatim_template.vala, do not modify */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#if !defined(VALA_EXTERN)
+#if defined(_MSC_VER)
+#define VALA_EXTERN __declspec(dllexport) extern
+#elif __GNUC__ >= 4
+#define VALA_EXTERN __attribute__((visibility("default"))) extern
+#else
+#define VALA_EXTERN extern
+#endif
+#endif
+
+#define _g_free0(var) (var = (g_free (var), NULL))
+#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }
+#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
+#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+
+VALA_EXTERN const gchar* m (void);
+static void _vala_main (void);
+
+const gchar*
+m (void)
+{
+       const gchar* result;
+       result = "foo";
+       return result;
+}
+
+static const gchar*
+string_to_string (const gchar* self)
+{
+       const gchar* result;
+       g_return_val_if_fail (self != NULL, NULL);
+       result = self;
+       return result;
+}
+
+static void
+_vala_main (void)
+{
+       gchar* _result_ = NULL;
+       gchar* _tmp0_;
+       const gchar* _tmp1_;
+       gint i = 0;
+       gchar* _tmp2_;
+       gchar* _tmp3_;
+       const gchar* _tmp4_;
+       const gchar* _tmp5_;
+       gchar* _tmp6_;
+       const gchar* _tmp7_;
+       _tmp0_ = g_strdup ("");
+       _g_free0 (_result_);
+       _result_ = _tmp0_;
+       _tmp1_ = _result_;
+       _vala_assert (g_strcmp0 (_tmp1_, "") == 0, "result == \"\"");
+       i = 42;
+       _tmp2_ = g_strdup_printf ("%i", i);
+       _tmp3_ = _tmp2_;
+       _tmp4_ = m ();
+       _tmp5_ = string_to_string (_tmp4_);
+       _tmp6_ = g_strconcat ("i=", _tmp3_, " \nm=", _tmp5_, " \n", "$", NULL);
+       _g_free0 (_result_);
+       _result_ = _tmp6_;
+       _g_free0 (_tmp3_);
+       _tmp7_ = _result_;
+       _vala_assert (g_strcmp0 (_tmp7_, "i=42 \nm=foo \n$") == 0, "result == \"i=42 \\nm=foo \\n$\"");
+       _g_free0 (_result_);
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main ();
+       return 0;
+}
+
diff --git a/tests/parser/verbatim-template.vala b/tests/parser/verbatim-template.vala
new file mode 100644 (file)
index 0000000..4a3db1f
--- /dev/null
@@ -0,0 +1,15 @@
+unowned string m () {
+       return "foo";
+}
+
+void main () {
+       string result;
+       result = @"""""";
+       assert (result == "");
+
+       int i = 42;
+       result = @"""i=$i 
+m=$(m ()) 
+$$""";
+       assert (result == "i=42 \nm=foo \n$");
+}
diff --git a/tests/scanner/string-template.c-expected b/tests/scanner/string-template.c-expected
new file mode 100644 (file)
index 0000000..eb6821b
--- /dev/null
@@ -0,0 +1,57 @@
+/* scanner_string_template.c generated by valac, the Vala compiler
+ * generated from scanner_string_template.vala, do not modify */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#define _g_free0(var) (var = (g_free (var), NULL))
+
+static void _vala_main (void);
+
+static const gchar*
+string_to_string (const gchar* self)
+{
+       const gchar* result;
+       g_return_val_if_fail (self != NULL, NULL);
+       result = self;
+       return result;
+}
+
+static void
+_vala_main (void)
+{
+       gchar* foo = NULL;
+       gchar* _tmp0_;
+       gchar* bar = NULL;
+       gchar* _tmp1_;
+       gchar* manam = NULL;
+       const gchar* _tmp2_;
+       const gchar* _tmp3_;
+       gchar* _tmp4_;
+       gchar* minim = NULL;
+       gchar* _tmp5_;
+       _tmp0_ = g_strdup ("Hello");
+       foo = _tmp0_;
+       _tmp1_ = g_strdup ("world");
+       bar = _tmp1_;
+       _tmp2_ = string_to_string (foo);
+       _tmp3_ = string_to_string (bar);
+       _tmp4_ = g_strconcat (_tmp2_, " ", _tmp3_, "!", NULL);
+       manam = _tmp4_;
+       _tmp5_ = g_strdup ("");
+       minim = _tmp5_;
+       _g_free0 (minim);
+       _g_free0 (manam);
+       _g_free0 (bar);
+       _g_free0 (foo);
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main ();
+       return 0;
+}
+
diff --git a/tests/scanner/string-template.vala b/tests/scanner/string-template.vala
new file mode 100644 (file)
index 0000000..3d4a00d
--- /dev/null
@@ -0,0 +1,8 @@
+void main () {
+       var foo = "Hello";
+       var bar = "world";
+
+       var manam = @"$foo $bar!";
+       var minim = @"";
+}
+
diff --git a/tests/scanner/string-verbatim-template.c-expected b/tests/scanner/string-verbatim-template.c-expected
new file mode 100644 (file)
index 0000000..6f7b0d2
--- /dev/null
@@ -0,0 +1,57 @@
+/* scanner_string_verbatim_template.c generated by valac, the Vala compiler
+ * generated from scanner_string_verbatim_template.vala, do not modify */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#define _g_free0(var) (var = (g_free (var), NULL))
+
+static void _vala_main (void);
+
+static const gchar*
+string_to_string (const gchar* self)
+{
+       const gchar* result;
+       g_return_val_if_fail (self != NULL, NULL);
+       result = self;
+       return result;
+}
+
+static void
+_vala_main (void)
+{
+       gchar* foo = NULL;
+       gchar* _tmp0_;
+       gchar* bar = NULL;
+       gchar* _tmp1_;
+       gchar* manam = NULL;
+       const gchar* _tmp2_;
+       const gchar* _tmp3_;
+       gchar* _tmp4_;
+       gchar* minim = NULL;
+       gchar* _tmp5_;
+       _tmp0_ = g_strdup ("Hello");
+       foo = _tmp0_;
+       _tmp1_ = g_strdup ("world");
+       bar = _tmp1_;
+       _tmp2_ = string_to_string (foo);
+       _tmp3_ = string_to_string (bar);
+       _tmp4_ = g_strconcat (_tmp2_, " \n", _tmp3_, "!", NULL);
+       manam = _tmp4_;
+       _tmp5_ = g_strdup ("");
+       minim = _tmp5_;
+       _g_free0 (minim);
+       _g_free0 (manam);
+       _g_free0 (bar);
+       _g_free0 (foo);
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main ();
+       return 0;
+}
+
diff --git a/tests/scanner/string-verbatim-template.vala b/tests/scanner/string-verbatim-template.vala
new file mode 100644 (file)
index 0000000..32ff857
--- /dev/null
@@ -0,0 +1,8 @@
+void main () {
+       var foo = "Hello";
+       var bar = "world";
+
+       var manam = @"""$foo 
+$bar!""";
+       var minim = @"""""";
+}
index 7c7c483093789389797f2876afa5d7e86016efb4..9781cd3390ecc4ffa6f7245b82fc6ef679acfb83 100644 (file)
@@ -394,6 +394,11 @@ public class Vala.Genie.Parser : CodeVisitor {
                        string raw_string = get_last_string ();
                        string escaped_string = raw_string.substring (3, raw_string.length - 6).escape ("");
                        return new StringLiteral ("\"%s\"".printf (escaped_string), get_src (begin));
+               case TokenType.VERBATIM_TEMPLATE_STRING_LITERAL:
+                       next ();
+                       string raw_string = get_last_string ();
+                       string escaped_string = raw_string.escape ("");
+                       return new StringLiteral ("\"%s\"".printf (escaped_string), get_src (begin));
                case TokenType.NULL:
                        next ();
                        return new NullLiteral (get_src (begin));
@@ -701,6 +706,7 @@ public class Vala.Genie.Parser : CodeVisitor {
                case TokenType.STRING_LITERAL:
                case TokenType.TEMPLATE_STRING_LITERAL:
                case TokenType.VERBATIM_STRING_LITERAL:
+               case TokenType.VERBATIM_TEMPLATE_STRING_LITERAL:
                case TokenType.NULL:
                        expr = parse_literal ();
                        break;
@@ -1285,6 +1291,7 @@ public class Vala.Genie.Parser : CodeVisitor {
                                        case TokenType.STRING_LITERAL:
                                        case TokenType.TEMPLATE_STRING_LITERAL:
                                        case TokenType.VERBATIM_STRING_LITERAL:
+                                       case TokenType.VERBATIM_TEMPLATE_STRING_LITERAL:
                                        case TokenType.NULL:
                                        case TokenType.SELF:
                                        case TokenType.SUPER:
index ef54ae7d38306ca74e831ee6e2135afdf85a0bed..286992206868a96cf52690e58ad1a5f4cd0741f6 100644 (file)
@@ -67,7 +67,8 @@ public class Vala.Genie.Scanner {
                BRACKET,
                REGEX_LITERAL,
                TEMPLATE,
-               TEMPLATE_PART
+               TEMPLATE_PART,
+               VERBATIM_TEMPLATE
        }
 
        public Scanner (SourceFile source_file) {
@@ -97,6 +98,10 @@ public class Vala.Genie.Scanner {
                return (state_stack.length > 0 && state_stack[state_stack.length - 1] == State.TEMPLATE);
        }
 
+       bool in_verbatim_template () {
+               return (state_stack.length > 0 && state_stack[state_stack.length - 1] == State.VERBATIM_TEMPLATE);
+       }
+
        bool in_template_part () {
                return (state_stack.length > 0 && state_stack[state_stack.length - 1] == State.TEMPLATE_PART);
        }
@@ -695,6 +700,7 @@ public class Vala.Genie.Scanner {
 
 
        public TokenType read_template_token (out SourceLocation token_begin, out SourceLocation token_end) {
+               bool is_verbatim = in_verbatim_template ();
                TokenType type;
                char* begin = current;
                token_begin = SourceLocation (begin, line, column);
@@ -706,9 +712,22 @@ public class Vala.Genie.Scanner {
                } else {
                        switch (current[0]) {
                        case '"':
-                               type = TokenType.CLOSE_TEMPLATE;
-                               current++;
-                               state_stack.length--;
+                               if (is_verbatim) {
+                                       if (current < end -2 && current[1] == '"' && current[2] == '"' && current[3] != '"') {
+                                               type = TokenType.CLOSE_TEMPLATE;
+                                               current += 3;
+                                               state_stack.length--;
+                                       } else {
+                                               type = TokenType.VERBATIM_TEMPLATE_STRING_LITERAL;
+                                               current++;
+                                               token_length_in_chars++;
+                                               state_stack += State.TEMPLATE_PART;
+                                       }
+                               } else {
+                                       type = TokenType.CLOSE_TEMPLATE;
+                                       current++;
+                                       state_stack.length--;
+                               }
                                break;
                        case '$':
                                token_begin.pos++; // $ is not part of following token
@@ -727,7 +746,7 @@ public class Vala.Genie.Scanner {
                                        state_stack += State.PARENS;
                                        return read_token (out token_begin, out token_end);
                                } else if (current[0] == '$') {
-                                       type = TokenType.TEMPLATE_STRING_LITERAL;
+                                       type = is_verbatim ? TokenType.VERBATIM_TEMPLATE_STRING_LITERAL : TokenType.TEMPLATE_STRING_LITERAL;
                                        current++;
                                        state_stack += State.TEMPLATE_PART;
                                } else {
@@ -736,10 +755,10 @@ public class Vala.Genie.Scanner {
                                }
                                break;
                        default:
-                               type = TokenType.TEMPLATE_STRING_LITERAL;
+                               type = is_verbatim ? TokenType.VERBATIM_TEMPLATE_STRING_LITERAL : TokenType.TEMPLATE_STRING_LITERAL;
                                token_length_in_chars = 0;
                                while (current < end && current[0] != '"' && current[0] != '$') {
-                                       if (current[0] == '\\') {
+                                       if (current[0] == '\\' && !is_verbatim) {
                                                current++;
                                                token_length_in_chars++;
                                                if (current >= end) {
@@ -842,7 +861,7 @@ public class Vala.Genie.Scanner {
                        return TokenType.EOF;
                }
 
-               if (in_template ()) {
+               if (in_template () || in_verbatim_template ()) {
                        return read_template_token (out token_begin, out token_end);
                } else if (in_template_part ()) {
                        state_stack.length--;
@@ -960,9 +979,15 @@ public class Vala.Genie.Scanner {
                        type = get_identifier_or_keyword (begin, len);
                } else if (current[0] == '@') {
                        if (current < end - 1 && current[1] == '"') {
+                               current += 1;
+                               if (current < end - 5 && current[1] == '"' && current[2] == '"') {
+                                       current += 3;
+                                       state_stack += State.VERBATIM_TEMPLATE;
+                               } else {
+                                       current += 1;
+                                       state_stack += State.TEMPLATE;
+                               }
                                type = TokenType.OPEN_TEMPLATE;
-                               current += 2;
-                               state_stack += State.TEMPLATE;
                        } else {
                                token_begin.pos++; // @ is not part of the identifier
                                current++;
@@ -1053,7 +1078,7 @@ public class Vala.Genie.Scanner {
                                if (state_stack.length > 0) {
                                        state_stack.length--;
                                }
-                               if (in_template ()) {
+                               if (in_template () || in_verbatim_template ()) {
                                        type = TokenType.COMMA;
                                }
                                break;
index 08bef53fddd3c814cc0bca59ea64509b6c33a288..fc46724b42bad5a81bbff341a7ecd2cb0feb012c 100644 (file)
@@ -163,6 +163,7 @@ public enum Vala.Genie.TokenType {
        USES,
        VAR,
        VERBATIM_STRING_LITERAL,
+       VERBATIM_TEMPLATE_STRING_LITERAL,
        VIRTUAL,
        VOID,
        VOLATILE,
@@ -311,6 +312,7 @@ public enum Vala.Genie.TokenType {
                case USES: return "`uses'";
                case VAR: return "`var'";
                case VERBATIM_STRING_LITERAL: return "verbatim string literal";
+               case VERBATIM_TEMPLATE_STRING_LITERAL: return "verbatim template string literal";
                case VIRTUAL: return "`virtual'";
                case VOID: return "`void'";
                case VOLATILE: return "`volatile'";
index f703e9c86749003ac6dec01601e8d5b90dc35e42..23b1e7db438bd87c2a61b10054a82d0ae086dbe2 100644 (file)
@@ -384,6 +384,11 @@ public class Vala.Parser : CodeVisitor {
                        string raw_string = get_last_string ();
                        string escaped_string = raw_string.substring (3, raw_string.length - 6).escape ("");
                        return new StringLiteral ("\"%s\"".printf (escaped_string), get_src (begin));
+               case TokenType.VERBATIM_TEMPLATE_STRING_LITERAL:
+                       next ();
+                       string raw_string = get_last_string ();
+                       string escaped_string = raw_string.escape ("");
+                       return new StringLiteral ("\"%s\"".printf (escaped_string), get_src (begin));
                case TokenType.NULL:
                        next ();
                        return new NullLiteral (get_src (begin));
@@ -719,6 +724,7 @@ public class Vala.Parser : CodeVisitor {
                case TokenType.REGEX_LITERAL:
                case TokenType.TEMPLATE_STRING_LITERAL:
                case TokenType.VERBATIM_STRING_LITERAL:
+               case TokenType.VERBATIM_TEMPLATE_STRING_LITERAL:
                case TokenType.NULL:
                        expr = parse_literal ();
                        break;
@@ -1269,6 +1275,7 @@ public class Vala.Parser : CodeVisitor {
                                                case TokenType.STRING_LITERAL:
                                                case TokenType.TEMPLATE_STRING_LITERAL:
                                                case TokenType.VERBATIM_STRING_LITERAL:
+                                               case TokenType.VERBATIM_TEMPLATE_STRING_LITERAL:
                                                case TokenType.REGEX_LITERAL:
                                                case TokenType.NULL:
                                                case TokenType.THIS:
index daeb97febe3a4c65e72297f3ee95effa3bafaf17..13a4698b66bacd63640ee5828bdc0abdcc3d5b30 100644 (file)
@@ -54,7 +54,8 @@ public class Vala.Scanner {
                BRACKET,
                TEMPLATE,
                TEMPLATE_PART,
-               REGEX_LITERAL
+               REGEX_LITERAL,
+               VERBATIM_TEMPLATE
        }
 
        public Scanner (SourceFile source_file) {
@@ -82,6 +83,10 @@ public class Vala.Scanner {
                return (state_stack.length > 0 && state_stack[state_stack.length - 1] == State.TEMPLATE);
        }
 
+       bool in_verbatim_template () {
+               return (state_stack.length > 0 && state_stack[state_stack.length - 1] == State.VERBATIM_TEMPLATE);
+       }
+
        bool in_template_part () {
                return (state_stack.length > 0 && state_stack[state_stack.length - 1] == State.TEMPLATE_PART);
        }
@@ -686,6 +691,7 @@ public class Vala.Scanner {
        }
 
        public TokenType read_template_token (out SourceLocation token_begin, out SourceLocation token_end) {
+               bool is_verbatim = in_verbatim_template ();
                TokenType type;
                char* begin = current;
                token_begin = SourceLocation (begin, line, column);
@@ -697,9 +703,22 @@ public class Vala.Scanner {
                } else {
                        switch (current[0]) {
                        case '"':
-                               type = TokenType.CLOSE_TEMPLATE;
-                               current++;
-                               state_stack.length--;
+                               if (is_verbatim) {
+                                       if (current < end -2 && current[1] == '"' && current[2] == '"' && current[3] != '"') {
+                                               type = TokenType.CLOSE_TEMPLATE;
+                                               current += 3;
+                                               state_stack.length--;
+                                       } else {
+                                               type = TokenType.VERBATIM_TEMPLATE_STRING_LITERAL;
+                                               current++;
+                                               token_length_in_chars++;
+                                               state_stack += State.TEMPLATE_PART;
+                                       }
+                               } else {
+                                       type = TokenType.CLOSE_TEMPLATE;
+                                       current++;
+                                       state_stack.length--;
+                               }
                                break;
                        case '$':
                                token_begin.pos++; // $ is not part of following token
@@ -718,7 +737,7 @@ public class Vala.Scanner {
                                        state_stack += State.PARENS;
                                        return read_token (out token_begin, out token_end);
                                } else if (current[0] == '$') {
-                                       type = TokenType.TEMPLATE_STRING_LITERAL;
+                                       type = is_verbatim ? TokenType.VERBATIM_TEMPLATE_STRING_LITERAL : TokenType.TEMPLATE_STRING_LITERAL;
                                        current++;
                                        state_stack += State.TEMPLATE_PART;
                                } else {
@@ -727,10 +746,10 @@ public class Vala.Scanner {
                                }
                                break;
                        default:
-                               type = TokenType.TEMPLATE_STRING_LITERAL;
+                               type = is_verbatim ? TokenType.VERBATIM_TEMPLATE_STRING_LITERAL : TokenType.TEMPLATE_STRING_LITERAL;
                                token_length_in_chars = 0;
                                while (current < end && current[0] != '"' && current[0] != '$') {
-                                       if (current[0] == '\\') {
+                                       if (current[0] == '\\' && !is_verbatim) {
                                                current++;
                                                token_length_in_chars++;
                                                if (current >= end) {
@@ -829,7 +848,7 @@ public class Vala.Scanner {
        }
 
        public TokenType read_token (out SourceLocation token_begin, out SourceLocation token_end) {
-               if (in_template ()) {
+               if (in_template () || in_verbatim_template ()) {
                        return read_template_token (out token_begin, out token_end);
                } else if (in_template_part ()) {
                        state_stack.length--;
@@ -861,9 +880,15 @@ public class Vala.Scanner {
                        type = get_identifier_or_keyword (begin, len);
                } else if (current[0] == '@') {
                        if (current < end - 1 && current[1] == '"') {
+                               current += 1;
+                               if (current < end - 5 && current[1] == '"' && current[2] == '"') {
+                                       current += 3;
+                                       state_stack += State.VERBATIM_TEMPLATE;
+                               } else {
+                                       current += 1;
+                                       state_stack += State.TEMPLATE;
+                               }
                                type = TokenType.OPEN_TEMPLATE;
-                               current += 2;
-                               state_stack += State.TEMPLATE;
                        } else {
                                token_begin.pos++; // @ is not part of the identifier
                                current++;
@@ -901,7 +926,7 @@ public class Vala.Scanner {
                                if (state_stack.length > 0) {
                                        state_stack.length--;
                                }
-                               if (in_template ()) {
+                               if (in_template () || in_verbatim_template ()) {
                                        type = TokenType.COMMA;
                                }
                                break;
index 2c64ec1b00c618715858303191e8991a835afb46..6097beaff001571a32c7df5052531341c8068c64 100644 (file)
@@ -149,6 +149,7 @@ public enum Vala.TokenType {
        USING,
        VAR,
        VERBATIM_STRING_LITERAL,
+       VERBATIM_TEMPLATE_STRING_LITERAL,
        VIRTUAL,
        VOID,
        VOLATILE,
@@ -284,6 +285,7 @@ public enum Vala.TokenType {
                case USING: return "`using'";
                case VAR: return "`var'";
                case VERBATIM_STRING_LITERAL: return "verbatim string literal";
+               case VERBATIM_TEMPLATE_STRING_LITERAL: return "verbatim template string literal";
                case VIRTUAL: return "`virtual'";
                case VOID: return "`void'";
                case VOLATILE: return "`volatile'";