Skip to content
Commits on Source (99)
......@@ -10,4 +10,3 @@ Email, github, bugzilla (in gnome-builder project), etc.
We follow the GLib and Gtk+ coding style, which is roughly GNU C89.
Please don't use the new g_auto() and g_autoptr() since we would like
this to work on other platforms without much effort.
==============
Version 3.35.0
==============
This is a development release, not intended for end users.
Changes in this release:
• Build system improvements and test suites
• Many fixes to TmplExpr lexing, parsing, and evaluation
• A number of new AST nodes and symbo API
• Various new builtin functions
• Improved support for swallowing newlines from templates
==============
Version 3.34.1
==============
......
......@@ -25,7 +25,7 @@ private_headers = [
'tmpl-util-private.h',
]
glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix')
glib_prefix = dependency('glib-2.0').get_variable('prefix')
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
......@@ -51,4 +51,3 @@ gnome.gtkdoc('template-glib',
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'gio')),
],
install: true)
ent_conf = configuration_data()
ent_conf.set('PACKAGE', 'Template-GLib')
ent_conf.set('PACKAGE_BUGREPORT', 'https://bugzilla.gnome.org/enter_bug.cgi?product=template-glib')
ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.gnome.org/GNOME/template-glib/-/issues')
ent_conf.set('PACKAGE_NAME', 'Template-GLib')
ent_conf.set('PACKAGE_STRING', 'template-glib')
ent_conf.set('PACKAGE_TARNAME', 'template-glib-' + meson.project_version())
ent_conf.set('PACKAGE_URL', 'http://wiki.gnome.org/Apps/Builder')
ent_conf.set('PACKAGE_URL', 'https://gitlab.gnome.org/GNOME/template-glib')
ent_conf.set('PACKAGE_VERSION', meson.project_version())
ent_conf.set('PACKAGE_API_VERSION', apiversion)
configure_file(input: 'gtkdocentities.ent.in', output: 'gtkdocentities.ent', configuration: ent_conf)
project('template-glib', 'c',
version: '3.34.1',
version: '3.35.0',
license: 'LGPLv2.1+',
meson_version: '>= 0.50.0',
default_options: [ 'warning_level=1', 'buildtype=debugoptimized', 'c_std=gnu11' ],
meson_version: '>= 0.51.0',
default_options: [ 'warning_level=2', 'buildtype=debugoptimized', 'c_std=gnu11' ],
)
package_subdir = get_option('package_subdir')
if meson.is_subproject() and package_subdir == ''
error('-Dpackage_subdir must be set when using @0@ as a subproject'.format(meson.project_name()))
endif
version_arr = meson.project_version().split('.')
template_glib_version_major = version_arr[0].to_int()
template_glib_version_minor = version_arr[1].to_int()
......@@ -32,6 +38,29 @@ config_h = configuration_data()
config_h.set_quoted('GETTEXT_PACKAGE', 'libtemplate_glib')
config_h.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
cc = meson.get_compiler('c')
release_args = []
global_link_args = []
test_link_args = [
'-Wl,-z,relro',
'-Wl,-z,now',
]
if not get_option('buildtype').startswith('debug')
add_project_arguments(['-DG_DISABLE_CAST_CHECKS'], language: 'c')
release_args += [ '-DG_DISABLE_ASSERT' ]
test_link_args += [
'-Wl,-Bsymbolic',
'-fno-plt',
]
endif
foreach link_arg: test_link_args
if cc.links('int main () { return 0; }', name: link_arg, args: link_arg)
global_link_args += link_arg
endif
endforeach
add_project_link_arguments(global_link_args, language: 'c')
configure_file(
output: 'config.h',
configuration: config_h,
......@@ -81,7 +110,7 @@ test_c_args = [
if get_option('buildtype') != 'plain'
test_c_args += '-fstack-protector-strong'
endif
if get_option('enable_profiling')
if get_option('profiling')
test_c_args += '-pg'
endif
......@@ -96,7 +125,6 @@ add_project_arguments(
)
# Setup various paths that subdirectory meson.build files need
package_subdir = get_option('package_subdir')
libdir = join_paths(get_option('libdir'), package_subdir)
includedir = join_paths(get_option('includedir'), package_subdir)
girdir = join_paths(get_option('datadir'), package_subdir, 'gir-1.0')
......@@ -110,10 +138,17 @@ endif
gnome = import('gnome')
i18n = import('i18n')
gir = find_program('g-ir-scanner', required: get_option('introspection'))
generate_gir = gir.found() and (not meson.is_cross_build() or get_option('introspection').enabled())
generate_vapi = generate_gir and get_option('vapi')
subdir('src')
subdir('tests')
subdir('po')
if get_option('enable_gtk_doc')
if get_option('tests')
subdir('tests')
endif
if get_option('gtk_doc')
subdir('doc')
endif
# Performance and debugging related options
option('enable_tracing', type: 'boolean', value: false)
option('enable_profiling', type: 'boolean', value: false)
option('tracing', type: 'boolean', value: false)
option('profiling', type: 'boolean', value: false)
# Support for multiple languages
option('with_introspection', type: 'boolean', value: true)
option('with_vapi', type: 'boolean', value: true)
option('introspection', type: 'feature', value: 'auto')
option('vapi', type: 'boolean', value: true)
# For subproject usage
option('package_subdir', type: 'string',
description: 'Private sub-directory used when built as a subproject'
)
option('enable_gtk_doc',
option('gtk_doc',
type: 'boolean', value: false,
description: 'Whether to generate the API reference for Template-GLib')
option('tests', type: 'boolean', value: true)
......@@ -6,7 +6,7 @@ version_data.set('TMPL_MAJOR_VERSION', template_glib_version_major)
version_data.set('TMPL_MINOR_VERSION', template_glib_version_minor)
version_data.set('TMPL_MICRO_VERSION', template_glib_version_micro)
version_data.set('TMPL_VERSION', meson.project_version())
version_data.set10('ENABLE_TRACING', get_option('enable_tracing'))
version_data.set10('ENABLE_TRACING', get_option('tracing'))
tmpl_version_h = configure_file(
input: 'tmpl-version.h.in',
......@@ -68,7 +68,6 @@ libtemplate_glib_deps = [
cc.find_library('m', required: false),
]
flex = find_program('flex')
bison = find_program('bison')
sed = find_program('sed')
......@@ -96,7 +95,6 @@ tmpl_expr_scanner = custom_target('tmpl-expr-scanner',
command: [flex, '-o', '@OUTPUT@', '@INPUT@']
)
libtemplate_glib_sources = [
libtemplate_glib_generated_headers,
libtemplate_glib_public_headers,
......@@ -135,14 +133,21 @@ libtemplate_glib_sources = [
'tmpl-util.c',
]
if libdir == '' or includedir == ''
error('You must set pkglibdir and pkgincludedir when using as a subproject')
endif
core_lib = static_library('template_glib', libtemplate_glib_sources,
dependencies: libtemplate_glib_deps,
c_args: release_args,
)
core_lib_dep = declare_dependency(
sources: libtemplate_glib_generated_headers,
dependencies: libtemplate_glib_deps,
link_whole: core_lib,
include_directories: include_directories('.'),
)
libtemplate_glib = library(
'template_glib-' + apiversion,
libtemplate_glib_sources,
link_whole: core_lib,
dependencies: libtemplate_glib_deps,
soversion: soversion,
version: libversion,
......@@ -157,15 +162,12 @@ libtemplate_glib_dep = declare_dependency(
include_directories: include_directories('.'),
)
if get_option('with_introspection')
if girdir == '' or typelibdir == ''
error('You must set pkggirdir and pkgtypelidir when using as a subproject')
endif
if generate_gir
libtemplate_glib_gir = gnome.generate_gir(libtemplate_glib,
sources: libtemplate_glib_generated_headers + libtemplate_glib_public_headers + libtemplate_glib_public_sources,
nsversion: apiversion,
namespace: 'Template',
export_packages: 'template-glib-@0@'.format(apiversion),
symbol_prefix: 'tmpl',
identifier_prefix: 'Tmpl',
link_with: libtemplate_glib,
......@@ -179,11 +181,7 @@ if get_option('with_introspection')
],
)
if get_option('with_vapi')
if vapidir == ''
error('You must set pkgvapidir when using as a subproject')
endif
if get_option('vapi')
libtemplate_glib_vapi = gnome.generate_vapi('template-glib-' + apiversion,
sources: libtemplate_glib_gir[0],
packages: [ 'gio-2.0' ],
......@@ -198,6 +196,10 @@ install_headers(libtemplate_glib_public_headers,
install_dir: libtemplate_glib_header_dir
)
if meson.version().version_compare('>=0.57')
meson.override_dependency('template-glib-@0@'.format(apiversion), libtemplate_glib_dep)
endif
pkgg = import('pkgconfig')
pkgg.generate(
......@@ -210,4 +212,3 @@ pkgg.generate(
requires: 'gio-2.0',
install_dir: join_paths(libdir, 'pkgconfig'),
)
This diff is collapsed.
%pure-parser
%define api.pure
%define parse.error verbose
%name-prefix "tmpl_expr_parser_"
%defines
%error-verbose
%parse-param { TmplExprParser *parser }
%lex-param { void *scanner }
......@@ -26,6 +26,7 @@
TmplExprBuiltin fn; /* builtin call */
int b; /* boolean */
int cmp; /* comparison */
int boolcmp; /* boolean comparison */
}
%{
......@@ -44,19 +45,89 @@ tmpl_expr_parser_error (TmplExprParser *parser,
parser->error_str = g_strdup (message);
}
static void
add_expr_to_parser (TmplExprParser *parser,
TmplExpr *node)
{
if (parser->ast != NULL)
{
if (parser->ast->any.type != TMPL_EXPR_STMT_LIST)
{
GPtrArray *ar = g_ptr_array_new_with_free_func ((GDestroyNotify)tmpl_expr_unref);
g_ptr_array_add (ar, parser->ast);
g_ptr_array_add (ar, node);
parser->ast = tmpl_expr_new_stmt_list (ar);
}
else
{
g_ptr_array_add (parser->ast->stmt_list.stmts, node);
}
}
else
{
parser->ast = node;
}
}
static TmplExpr *
create_function (char *name,
GPtrArray *symlist,
TmplExpr *list)
{
char **strv = NULL;
if (symlist != NULL)
{
g_ptr_array_add (symlist, NULL);
strv = (char **)(gpointer)g_ptr_array_free (symlist, FALSE);
}
return tmpl_expr_new_func (name, strv, list);
}
static void
define_function (TmplExprParser *parser,
char *name,
GPtrArray *symlist,
TmplExpr *list)
{
add_expr_to_parser (parser, create_function (name, symlist, list));
}
static TmplExpr *
add_to_list (TmplExpr *stmt,
TmplExpr *list)
{
g_assert (stmt != NULL);
if (list == NULL)
{
GPtrArray *ar = g_ptr_array_new_with_free_func ((GDestroyNotify)tmpl_expr_unref);
g_ptr_array_add (ar, stmt);
return tmpl_expr_new_stmt_list (ar);
}
g_assert (list->any.type == TMPL_EXPR_STMT_LIST);
g_ptr_array_insert (list->stmt_list.stmts, 0, stmt);
return list;
}
# define scanner parser->scanner
%}
%token <b> BOOL
%token CONSTANT_NULL
%token <d> NUMBER
%token <s> NAME STRING_LITERAL
%token <fn> BUILTIN
%token <s> REQUIRE VERSION
%token EOL
%token DEF END
%token IF THEN ELSE WHILE DO FUNC
%token NOP
%nonassoc <cmp> CMP
%left <cmp> CMP
%left <boolcmp> BOOLCMP
%right '='
%left '+' '-'
%left '*' '/'
......@@ -71,27 +142,40 @@ tmpl_expr_parser_error (TmplExprParser *parser,
%%
expr: /* nothing */ EOL {
parser->ast = NULL;
YYACCEPT;
}
| stmt EOL {
parser->ast = $1;
add_expr_to_parser (parser, $1);
YYACCEPT;
}
| FUNC NAME '(' symlist ')' '=' list EOL {
/* todo: add ast node to define the expr on the scope
* when evaluated.
*/
//tmpl_scope_add_user_func (parser->scope, $2, $4, $7);
parser->ast = NULL;
| stmt ';' {
add_expr_to_parser (parser, $1);
YYACCEPT;
}
| DEF NAME '(' ')' EOL list END {
define_function (parser, $2, NULL, $6);
YYACCEPT;
}
| DEF NAME '(' ')' list END {
define_function (parser, $2, NULL, $5);
YYACCEPT;
}
| DEF NAME '(' ')' EOL END {
define_function (parser, $2, NULL, NULL);
YYACCEPT;
}
| DEF NAME '(' symlist ')' EOL list END {
define_function (parser, $2, $4, $7);
YYACCEPT;
}
| FUNC NAME '(' ')' '=' list EOL {
/* todo: add ast node to define the expr on the scope
* when evaluated.
*/
//tmpl_scope_add_user_func (parser->scope, $2, NULL, $6);
parser->ast = NULL;
| DEF NAME '(' symlist ')' list END {
define_function (parser, $2, $4, $6);
YYACCEPT;
}
| DEF NAME '(' symlist ')' EOL END {
define_function (parser, $2, $4, NULL);
YYACCEPT;
}
;
......@@ -110,16 +194,19 @@ stmt: IF exp THEN list {
list: /* nothing */ { $$ = NULL; }
| stmt ';' list {
if ($3 == NULL)
$$ = $1;
else
$$ = tmpl_expr_new_simple (TMPL_EXPR_STMT_LIST, $1, $3);
$$ = add_to_list ($1, $3);
}
| stmt EOL list {
$$ = add_to_list ($1, $3);
}
;
exp: exp CMP exp {
$$ = tmpl_expr_new_simple ($2, $1, $3);
}
| exp BOOLCMP exp {
$$ = tmpl_expr_new_simple ($2, $1, $3);
}
| exp '+' exp {
$$ = tmpl_expr_new_simple (TMPL_EXPR_ADD, $1, $3);
}
......@@ -144,55 +231,80 @@ exp: exp CMP exp {
| BOOL {
$$ = tmpl_expr_new_boolean ($1);
}
| CONSTANT_NULL {
$$ = tmpl_expr_new_null ();
}
| STRING_LITERAL {
$$ = tmpl_expr_new_string ($1+1, strlen($1) - 2);
$$ = tmpl_expr_new_string ($1, -1);
g_free ($1);
}
| NAME {
$$ = tmpl_expr_new_symbol_ref ($1);
g_free ($1);
}
| NAME '=' exp {
$$ = tmpl_expr_new_symbol_assign ($1, $3);
g_free ($1);
}
| BUILTIN '(' explist ')' {
$$ = tmpl_expr_new_fn_call ($1, $3);
}
| NAME '(' explist ')' {
$$ = tmpl_expr_new_user_fn_call ($1, $3);
g_free ($1);
}
| NAME '(' ')' {
$$ = tmpl_expr_new_user_fn_call ($1, NULL);
g_free ($1);
}
| exp '.' NAME '(' ')' {
$$ = tmpl_expr_new_gi_call ($1, $3, NULL);
g_free ($3);
}
| exp '.' NAME '(' explist ')' {
$$ = tmpl_expr_new_gi_call ($1, $3, $5);
g_free ($3);
}
| exp '.' NAME {
$$ = tmpl_expr_new_getattr ($1, $3);
}
| exp '.' VERSION {
$$ = tmpl_expr_new_getattr ($1, "version");
g_free ($3);
}
| exp '.' NAME '=' exp {
$$ = tmpl_expr_new_setattr ($1, $3, $5);
g_free ($3);
}
| BUILTIN '(' explist ')' {
$$ = tmpl_expr_new_fn_call ($1, $3);
| exp '(' ')' {
$$ = tmpl_expr_new_anon_call ($1, NULL);
}
| NAME '(' explist ')' {
$$ = tmpl_expr_new_user_fn_call ($1, $3);
}
| NAME '(' ')' {
$$ = tmpl_expr_new_user_fn_call ($1, NULL);
| exp '(' explist ')' {
$$ = tmpl_expr_new_anon_call ($1, $3);
}
| '!' exp {
$$ = tmpl_expr_new_invert_boolean ($2);
}
| NOP {
$$ = tmpl_expr_new_nop ();
}
| REQUIRE NAME {
$$ = tmpl_expr_new_require ($2, NULL);
g_free ($2);
}
| REQUIRE NAME VERSION STRING_LITERAL {
char *vstr = g_strndup ($4+1, strlen($4)-2);
$$ = tmpl_expr_new_require ($2, vstr);
g_free (vstr);
$$ = tmpl_expr_new_require ($2, $4);
g_free ($2);
g_free ($4);
}
| FUNC '(' ')' stmt {
$$ = create_function (NULL, NULL, $4);
}
| FUNC '(' symlist ')' stmt {
$$ = create_function (NULL, $3, $5);
}
;
explist: exp
| exp ',' explist {
$$ = tmpl_expr_new_simple (TMPL_EXPR_STMT_LIST, $1, $3);
$$ = tmpl_expr_new_simple (TMPL_EXPR_ARGS, $1, $3);
}
;
......@@ -201,7 +313,8 @@ symlist: NAME {
g_ptr_array_add ($$, $1);
}
| NAME ',' symlist {
g_ptr_array_insert ($3, 0, $1);
$$ = $3;
g_ptr_array_insert ($$, 0, $1);
}
;
......@@ -60,6 +60,14 @@ typedef struct
TmplExpr *params;
} TmplExprUserFnCall;
typedef struct
{
TmplExprType type;
volatile gint ref_count;
TmplExpr *anon;
TmplExpr *params;
} TmplExprAnonFnCall;
typedef struct
{
TmplExprType type;
......@@ -136,12 +144,29 @@ typedef struct
volatile gint ref_count;
} TmplExprAny;
typedef struct
{
TmplExprType type;
volatile gint ref_count;
GPtrArray *stmts;
} TmplExprStmtList;
typedef struct
{
TmplExprType type;
volatile gint ref_count;
char *name;
char **symlist;
TmplExpr *list;
} TmplExprFunc;
union _TmplExpr
{
TmplExprAny any;
TmplExprSimple simple;
TmplExprGiCall gi_call;
TmplExprFnCall fn_call;
TmplExprAnonFnCall anon_fn_call;
TmplExprUserFnCall user_fn_call;
TmplExprFlow flow;
TmplExprNumber number;
......@@ -151,6 +176,8 @@ union _TmplExpr
TmplExprGetattr getattr;
TmplExprSetattr setattr;
TmplExprRequire require;
TmplExprStmtList stmt_list;
TmplExprFunc func;
};
G_END_DECLS
......
......@@ -16,6 +16,21 @@
#pragma GCC diagnostic ignored "-Wswitch-default"
#pragma GCC diagnostic ignored "-Wunused-function"
static char *
copy_literal (const char *str)
{
gsize len;
if (str[0] == 'L')
str++;
g_assert (str[0] == '\"');
str++;
len = strlen (str);
g_assert (len > 0);
g_assert (str[len-1] == '\"');
return g_strndup (str, len - 1);
}
%}
%option extra-type="TmplExprParser *"
......@@ -37,8 +52,8 @@ TmplExprParser *parser = yyextra;
"=" |
"," |
"." |
";" |
"!" |
";" |
"(" |
")" { return yytext [0]; }
......@@ -49,8 +64,10 @@ TmplExprParser *parser = yyextra;
"==" { yylval->cmp = TMPL_EXPR_EQ; return CMP; }
">=" { yylval->cmp = TMPL_EXPR_GTE; return CMP; }
"<=" { yylval->cmp = TMPL_EXPR_LTE; return CMP; }
"||" { yylval->cmp = TMPL_EXPR_OR; return CMP; }
"&&" { yylval->cmp = TMPL_EXPR_AND; return CMP; }
/* boolean ops */
"||" { yylval->boolcmp = TMPL_EXPR_OR; return BOOLCMP; }
"&&" { yylval->boolcmp = TMPL_EXPR_AND; return BOOLCMP; }
/* keywords */
"if" { return IF; }
......@@ -59,24 +76,56 @@ TmplExprParser *parser = yyextra;
"while" { return WHILE; }
"do" { return DO; }
"func" { return FUNC; }
"def" { return DEF; }
"end" { return END; }
"require" { return REQUIRE; }
"version" { return VERSION; }
"pass" { return NOP; }
/* booleans */
"true" { yylval->b = 1; return BOOL; }
"false" { yylval->b = 0; return BOOL; }
"True" { yylval->b = 1; return BOOL; }
"False" { yylval->b = 0; return BOOL; }
"TRUE" { yylval->b = 1; return BOOL; }
"FALSE" { yylval->b = 0; return BOOL; }
/* constants */
"null" { return CONSTANT_NULL; }
/* builtin functions */
"ceil" { yylval->fn = TMPL_EXPR_BUILTIN_CEIL; return BUILTIN; }
"floor" { yylval->fn = TMPL_EXPR_BUILTIN_FLOOR; return BUILTIN; }
"hex" { yylval->fn = TMPL_EXPR_BUILTIN_HEX; return BUILTIN; }
"log" { yylval->fn = TMPL_EXPR_BUILTIN_LOG; return BUILTIN; }
"print" { yylval->fn = TMPL_EXPR_BUILTIN_PRINT; return BUILTIN; }
"repr" { yylval->fn = TMPL_EXPR_BUILTIN_REPR; return BUILTIN; }
"sqrt" { yylval->fn = TMPL_EXPR_BUILTIN_SQRT; return BUILTIN; }
"typeof" { yylval->fn = TMPL_EXPR_BUILTIN_TYPEOF; return BUILTIN; }
"assert" { yylval->fn = TMPL_EXPR_BUILTIN_ASSERT; return BUILTIN; }
"abs" { yylval->fn = TMPL_EXPR_BUILTIN_ABS; return BUILTIN; }
"ceil" { yylval->fn = TMPL_EXPR_BUILTIN_CEIL; return BUILTIN; }
"floor" { yylval->fn = TMPL_EXPR_BUILTIN_FLOOR; return BUILTIN; }
"hex" { yylval->fn = TMPL_EXPR_BUILTIN_HEX; return BUILTIN; }
"log" { yylval->fn = TMPL_EXPR_BUILTIN_LOG; return BUILTIN; }
"print" { yylval->fn = TMPL_EXPR_BUILTIN_PRINT; return BUILTIN; }
"printerr" { yylval->fn = TMPL_EXPR_BUILTIN_PRINTERR; return BUILTIN; }
"repr" { yylval->fn = TMPL_EXPR_BUILTIN_REPR; return BUILTIN; }
"sqrt" { yylval->fn = TMPL_EXPR_BUILTIN_SQRT; return BUILTIN; }
"typeof" { yylval->fn = TMPL_EXPR_BUILTIN_TYPEOF; return BUILTIN; }
"sin" { yylval->fn = TMPL_EXPR_BUILTIN_SIN; return BUILTIN; }
"tan" { yylval->fn = TMPL_EXPR_BUILTIN_TAN; return BUILTIN; }
"cos" { yylval->fn = TMPL_EXPR_BUILTIN_COS; return BUILTIN; }
"char" { yylval->fn = TMPL_EXPR_BUILTIN_CAST_CHAR; return BUILTIN; }
"byte" { yylval->fn = TMPL_EXPR_BUILTIN_CAST_BYTE; return BUILTIN; }
"i32" { yylval->fn = TMPL_EXPR_BUILTIN_CAST_I32; return BUILTIN; }
"u32" { yylval->fn = TMPL_EXPR_BUILTIN_CAST_U32; return BUILTIN; }
"i64" { yylval->fn = TMPL_EXPR_BUILTIN_CAST_I64; return BUILTIN; }
"u64" { yylval->fn = TMPL_EXPR_BUILTIN_CAST_U64; return BUILTIN; }
"float" { yylval->fn = TMPL_EXPR_BUILTIN_CAST_FLOAT; return BUILTIN; }
"double" { yylval->fn = TMPL_EXPR_BUILTIN_CAST_DOUBLE; return BUILTIN; }
"bool" { yylval->fn = TMPL_EXPR_BUILTIN_CAST_BOOL; return BUILTIN; }
/* string literals */
L?\"(\\.|[^\\"])*\" { yylval->s = yytext; return STRING_LITERAL; }
L?\"(\\.|[^\\"])*\" { yylval->s = copy_literal (yytext); return STRING_LITERAL; }
/* @ to escape reserved keywords */
@[a-zA-Z_][a-zA-Z0-9_]* {
yylval->s = g_strdup (yytext+1);
return NAME;
}
/* names */
[a-zA-Z_][a-zA-Z0-9_]* {
......@@ -88,8 +137,9 @@ L?\"(\\.|[^\\"])*\" { yylval->s = yytext; return STRING_LITERAL; }
"."?[0-9]+{EXP}? { yylval->d = atof(yytext); return NUMBER; }
"//".*
[ \t] /* ignore whitespace */
\\n { printf ("c> "); }
[ \t] /* ignore whitespace */
"\\\n" /* ignore escpaed newlines */
#[^\n]* { return EOL; } /* line-wise comments should EOL things */
"\n" { return EOL; }
<<EOF>> { parser->reached_eof = TRUE; return EOL; }
. {
......@@ -134,14 +184,18 @@ tmpl_expr_parser_parse_string (TmplExprParser *self,
GError **error)
{
YY_BUFFER_STATE buf;
gint ret;
int ret = 0;
g_return_val_if_fail (self != NULL, FALSE);
buf = tmpl_expr_parser__scan_string (input, self->scanner);
ret = tmpl_expr_parser_parse (self);
while (!self->reached_eof && ret == 0)
ret = tmpl_expr_parser_parse (self);
tmpl_expr_parser__delete_buffer (buf, self->scanner);
if (ret == 0 && self->error_str == NULL)
return TRUE;
if (self->error_str)
{
g_set_error (error,
......@@ -151,9 +205,6 @@ tmpl_expr_parser_parse_string (TmplExprParser *self,
return FALSE;
}
if (ret == 0)
return TRUE;
g_set_error (error,
TMPL_ERROR,
TMPL_ERROR_SYNTAX_ERROR,
......
......@@ -67,6 +67,7 @@ typedef enum
TMPL_EXPR_SYMBOL_REF,
TMPL_EXPR_SYMBOL_ASSIGN,
TMPL_EXPR_FN_CALL,
TMPL_EXPR_ANON_FN_CALL,
TMPL_EXPR_USER_FN_CALL,
TMPL_EXPR_GETATTR,
TMPL_EXPR_SETATTR,
......@@ -75,6 +76,10 @@ typedef enum
TMPL_EXPR_AND,
TMPL_EXPR_OR,
TMPL_EXPR_INVERT_BOOLEAN,
TMPL_EXPR_ARGS,
TMPL_EXPR_FUNC,
TMPL_EXPR_NOP,
TMPL_EXPR_NULL,
} TmplExprType;
typedef enum
......@@ -88,6 +93,20 @@ typedef enum
TMPL_EXPR_BUILTIN_REPR,
TMPL_EXPR_BUILTIN_SQRT,
TMPL_EXPR_BUILTIN_TYPEOF,
TMPL_EXPR_BUILTIN_ASSERT,
TMPL_EXPR_BUILTIN_SIN,
TMPL_EXPR_BUILTIN_TAN,
TMPL_EXPR_BUILTIN_COS,
TMPL_EXPR_BUILTIN_PRINTERR,
TMPL_EXPR_BUILTIN_CAST_BYTE,
TMPL_EXPR_BUILTIN_CAST_CHAR,
TMPL_EXPR_BUILTIN_CAST_I32,
TMPL_EXPR_BUILTIN_CAST_U32,
TMPL_EXPR_BUILTIN_CAST_I64,
TMPL_EXPR_BUILTIN_CAST_U64,
TMPL_EXPR_BUILTIN_CAST_FLOAT,
TMPL_EXPR_BUILTIN_CAST_DOUBLE,
TMPL_EXPR_BUILTIN_CAST_BOOL,
} TmplExprBuiltin;
TMPL_AVAILABLE_IN_ALL
......
......@@ -77,17 +77,26 @@ tmpl_expr_destroy (TmplExpr *self)
case TMPL_EXPR_LTE:
case TMPL_EXPR_MUL:
case TMPL_EXPR_NE:
case TMPL_EXPR_STMT_LIST:
case TMPL_EXPR_SUB:
case TMPL_EXPR_UNARY_MINUS:
case TMPL_EXPR_USER_FN_CALL:
case TMPL_EXPR_AND:
case TMPL_EXPR_OR:
case TMPL_EXPR_INVERT_BOOLEAN:
case TMPL_EXPR_ARGS:
g_clear_pointer (&self->simple.left, tmpl_expr_unref);
g_clear_pointer (&self->simple.right, tmpl_expr_unref);
break;
case TMPL_EXPR_USER_FN_CALL:
g_clear_pointer (&self->user_fn_call.symbol, g_free);
g_clear_pointer (&self->user_fn_call.params, tmpl_expr_unref);
break;
case TMPL_EXPR_ANON_FN_CALL:
g_clear_pointer (&self->anon_fn_call.anon, tmpl_expr_unref);
g_clear_pointer (&self->user_fn_call.params, tmpl_expr_unref);
break;
case TMPL_EXPR_GETATTR:
g_clear_pointer (&self->getattr.attr, g_free);
g_clear_pointer (&self->getattr.left, tmpl_expr_unref);
......@@ -99,6 +108,10 @@ tmpl_expr_destroy (TmplExpr *self)
g_clear_pointer (&self->setattr.right, tmpl_expr_unref);
break;
case TMPL_EXPR_STMT_LIST:
g_clear_pointer (&self->stmt_list.stmts, g_ptr_array_unref);
break;
case TMPL_EXPR_BOOLEAN:
case TMPL_EXPR_NUMBER:
break;
......@@ -138,6 +151,18 @@ tmpl_expr_destroy (TmplExpr *self)
g_clear_pointer (&self->require.version, g_free);
break;
case TMPL_EXPR_FUNC:
g_clear_pointer (&self->func.name, g_free);
g_clear_pointer (&self->func.symlist, g_strfreev);
g_clear_pointer (&self->func.list, tmpl_expr_unref);
break;
case TMPL_EXPR_NOP:
case TMPL_EXPR_NULL:
/* This should never happen,
* but just log it if it does */
g_return_if_reached ();
default:
g_assert_not_reached ();
}
......@@ -145,6 +170,33 @@ tmpl_expr_destroy (TmplExpr *self)
g_slice_free (TmplExpr, self);
}
/**
* tmpl_expr_new_stmt_list:
* @stmts: (transfer full) (element-type TmplExpr): a #GPtrArray of
* #TmplExpr which will be evaluated in sequence.
*
* Creates a new statement list for which the last item will be
* used as the "return value" from execution.
*
* Returns: (transfer full): a new #TmplExpr
*
* Since: 3.36
*/
TmplExpr *
tmpl_expr_new_stmt_list (GPtrArray *stmts)
{
TmplExpr *ret;
g_return_val_if_fail (stmts != NULL, NULL);
g_ptr_array_set_free_func (stmts, (GDestroyNotify)tmpl_expr_unref);
ret = tmpl_expr_new (TMPL_EXPR_STMT_LIST);
((TmplExprStmtList *)ret)->stmts = stmts;
return ret;
}
TmplExpr *
tmpl_expr_new_boolean (gboolean value)
{
......@@ -349,3 +401,51 @@ tmpl_expr_from_string (const gchar *str,
return ret;
}
TmplExpr *
tmpl_expr_new_func (char *name,
char **symlist,
TmplExpr *list)
{
TmplExprFunc *ret;
if (list == NULL)
list = tmpl_expr_new_nop ();
ret = tmpl_expr_new (TMPL_EXPR_FUNC);
ret->name = name;
ret->symlist = symlist;
ret->list = list;
return (TmplExpr *)ret;
}
TmplExpr *
tmpl_expr_new_anon_call (TmplExpr *func,
TmplExpr *params)
{
TmplExprAnonFnCall *ret;
g_return_val_if_fail (func != NULL, NULL);
g_return_val_if_fail (func->any.type == TMPL_EXPR_FUNC, NULL);
ret = tmpl_expr_new (TMPL_EXPR_ANON_FN_CALL);
ret->anon = func;
ret->params = params;
return (TmplExpr *)ret;
}
TmplExpr *
tmpl_expr_new_nop (void)
{
static TmplExpr interned = { .any.type = TMPL_EXPR_NOP, .any.ref_count = 1 };
return tmpl_expr_ref (&interned);
}
TmplExpr *
tmpl_expr_new_null (void)
{
static TmplExpr interned = { .any.type = TMPL_EXPR_NULL, .any.ref_count = 1 };
return tmpl_expr_ref (&interned);
}
......@@ -84,6 +84,21 @@ TmplExpr *tmpl_expr_new_symbol_ref (const gchar *symbol);
TMPL_AVAILABLE_IN_ALL
TmplExpr *tmpl_expr_new_symbol_assign (const gchar *symbol,
TmplExpr *right);
TMPL_AVAILABLE_IN_3_36
TmplExpr *tmpl_expr_new_stmt_list (GPtrArray *stmts);
TMPL_AVAILABLE_IN_3_36
TmplExpr *tmpl_expr_new_func (char *name,
char **symlist,
TmplExpr *list);
TMPL_AVAILABLE_IN_3_36
TmplExpr *tmpl_expr_new_anon_call (TmplExpr *func,
TmplExpr *params);
TMPL_AVAILABLE_IN_3_36
TmplExpr *tmpl_expr_new_nop (void);
TMPL_AVAILABLE_IN_3_36
TmplExpr *tmpl_expr_new_null (void);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (TmplExpr, tmpl_expr_unref)
G_END_DECLS
......
......@@ -24,6 +24,8 @@ G_BEGIN_DECLS
#define TMPL_TYPE_TYPELIB (tmpl_typelib_get_type())
#define TMPL_TYPE_BASE_INFO (tmpl_base_info_get_type())
typedef GType (*TmplGTypeFunc) (void);
GType tmpl_typelib_get_type (void);
GType tmpl_base_info_get_type (void);
gboolean tmpl_gi_argument_from_g_value (const GValue *value,
......@@ -36,6 +38,9 @@ gboolean tmpl_gi_argument_to_g_value (GValue *value,
GIArgument *arg,
GITransfer xfer,
GError **error);
TmplGTypeFunc
tmpl_gi_get_gtype_func (GIBaseInfo *base_info);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GIBaseInfo, g_base_info_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GIArgInfo, g_base_info_unref)
......
......@@ -479,3 +479,25 @@ tmpl_gi_argument_to_g_value (GValue *value,
return FALSE;
}
TmplGTypeFunc
tmpl_gi_get_gtype_func (GIBaseInfo *base_info)
{
GITypelib *typelib;
const char *symbol_name;
TmplGTypeFunc symbol = NULL;
if (base_info == NULL || GI_INFO_TYPE_OBJECT != g_base_info_get_type (base_info))
return NULL;
if (!(typelib = g_base_info_get_typelib (base_info)))
return NULL;
if (!(symbol_name = g_object_info_get_type_init (base_info)))
return NULL;
if (!g_typelib_symbol (typelib, symbol_name, (gpointer *)&symbol))
return NULL;
return symbol;
}
......@@ -16,6 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "tmpl-gi-private.h"
#include "tmpl-scope.h"
#include "tmpl-symbol.h"
......@@ -319,7 +322,7 @@ tmpl_scope_set_variant (TmplScope *self,
g_return_if_fail (name != NULL);
tmpl_symbol_assign_variant (tmpl_scope_get_full (self, name, TRUE),
value);
value);
}
/**
......@@ -339,7 +342,7 @@ tmpl_scope_set_strv (TmplScope *self,
g_return_if_fail (name != NULL);
tmpl_symbol_assign_variant (tmpl_scope_get_full (self, name, TRUE),
g_variant_new_strv (value, -1));
g_variant_new_strv (value, -1));
}
/**
......@@ -402,3 +405,122 @@ tmpl_scope_set_resolver (TmplScope *self,
self->resolver_destroy = destroy;
}
}
/**
* tmpl_scope_require:
* @self: a #TmplScope
* @namespace_: the namespace to import into the scope
* @version: (nullable): the version of @namespace_ to import
*
* Imports @namespace_ into @self so it can be used by expressions.
*
* Returns: %TRUE if successful; otherwise %FALSE
*/
gboolean
tmpl_scope_require (TmplScope *self,
const char *namespace_,
const char *version)
{
GITypelib *typelib;
GValue value = G_VALUE_INIT;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (namespace_ != NULL, FALSE);
if (!(typelib = g_irepository_require (NULL, namespace_, version, 0, NULL)))
return FALSE;
g_value_init (&value, TMPL_TYPE_TYPELIB);
g_value_set_pointer (&value, typelib);
tmpl_scope_set_value (self, namespace_, &value);
g_value_unset (&value);
return TRUE;
}
static void
tmpl_scope_list_symbols_internal (TmplScope *self,
GPtrArray *ar,
gboolean recursive)
{
GHashTableIter iter;
const char *key;
g_assert (self != NULL);
g_assert (ar != NULL);
g_hash_table_iter_init (&iter, self->symbols);
while (g_hash_table_iter_next (&iter, (gpointer *)&key, NULL))
g_ptr_array_add (ar, g_strdup (key));
if (recursive && self->parent)
tmpl_scope_list_symbols_internal (self->parent, ar, recursive);
}
/**
* tmpl_scope_list_symbols:
* @self: a #TmplScope
* @recursive: if the parent scopes should be included
*
* Gets the names of all symbols within the scope.
*
* Returns: (array zero-terminated=1) (element-type utf8) (transfer full):
* an array containing the names of all symbols within the scope.
*/
char **
tmpl_scope_list_symbols (TmplScope *self,
gboolean recursive)
{
GPtrArray *ar;
g_return_val_if_fail (self != NULL, NULL);
ar = g_ptr_array_new ();
tmpl_scope_list_symbols_internal (self, ar, recursive);
g_ptr_array_add (ar, NULL);
return (char **)g_ptr_array_free (ar, FALSE);
}
void
tmpl_scope_set_null (TmplScope *self,
const char *name)
{
GValue value = G_VALUE_INIT;
g_value_init (&value, G_TYPE_POINTER);
g_value_set_pointer (&value, NULL);
tmpl_scope_set_value (self, name, &value);
}
/**
* tmpl_scope_dup_string:
* @self: a #TmplScope
*
* Gets a string if the symbol @name is a string.
*
* Otherwise, %NULL is returned.
*
* Returns: (transfer full) (nullable): a string or %NULL
*
* Since: 3.36
*/
char *
tmpl_scope_dup_string (TmplScope *self,
const char *name)
{
GValue value = G_VALUE_INIT;
TmplSymbol *symbol;
char *ret = NULL;
if (!(symbol = tmpl_scope_peek (self, name)))
return NULL;
tmpl_symbol_get_value (symbol, &value);
if (G_VALUE_HOLDS_STRING (&value))
ret = g_value_dup_string (&value);
g_value_unset (&value);
return ret;
}
......@@ -92,6 +92,19 @@ void tmpl_scope_set_resolver (TmplScope *self,
TmplScopeResolver resolver,
gpointer user_data,
GDestroyNotify destroy);
TMPL_AVAILABLE_IN_3_36
gboolean tmpl_scope_require (TmplScope *self,
const char *namespace_,
const char *version);
TMPL_AVAILABLE_IN_3_36
char **tmpl_scope_list_symbols (TmplScope *self,
gboolean recursive);
TMPL_AVAILABLE_IN_3_36
void tmpl_scope_set_null (TmplScope *self,
const char *name);
TMPL_AVAILABLE_IN_3_36
char *tmpl_scope_dup_string (TmplScope *self,
const char *name);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (TmplScope, tmpl_scope_unref)
......
......@@ -286,3 +286,23 @@ tmpl_symbol_assign_strv (TmplSymbol *self,
tmpl_symbol_assign_value (self, &value);
g_value_unset (&value);
}
gboolean
tmpl_symbol_holds (TmplSymbol *self,
GType type)
{
return self != NULL &&
self->type == TMPL_SYMBOL_VALUE &&
self->u.value.g_type == type;
}
gpointer
tmpl_symbol_get_boxed (TmplSymbol *self)
{
if (self != NULL &&
self->type == TMPL_SYMBOL_VALUE &&
G_VALUE_HOLDS_BOXED (&self->u.value))
return g_value_get_boxed (&self->u.value);
return NULL;
}
......@@ -37,9 +37,14 @@ TMPL_AVAILABLE_IN_ALL
void tmpl_symbol_unref (TmplSymbol *self);
TMPL_AVAILABLE_IN_ALL
TmplSymbolType tmpl_symbol_get_symbol_type (TmplSymbol *self);
TMPL_AVAILABLE_IN_3_36
gboolean tmpl_symbol_holds (TmplSymbol *self,
GType type);
TMPL_AVAILABLE_IN_ALL
void tmpl_symbol_get_value (TmplSymbol *self,
GValue *value);
TMPL_AVAILABLE_IN_3_36
gpointer tmpl_symbol_get_boxed (TmplSymbol *self);
TMPL_AVAILABLE_IN_ALL
TmplExpr *tmpl_symbol_get_expr (TmplSymbol *self,
GPtrArray **params);
......