Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/majn/tgl.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkenorb <kenorb@users.noreply.github.com>2019-02-03 01:06:50 +0300
committerkenorb <kenorb@users.noreply.github.com>2019-02-03 01:06:50 +0300
commit45b75ff1db696d76d8c1ab907c790901cea96dda (patch)
treeb8d9f19d2304c0038faefdc702ebc5cdf91d86e5
parentb3c9ce2256389945f2ac8bc01e1add3fe44ec99f (diff)
parentdb13dc4f51727d523fe04a9a40714d0b89234020 (diff)
Merge branch 'master' of https://github.com/BenWiederhake/tgl
-rw-r--r--.gitmodules3
-rw-r--r--Makefile.in9
-rw-r--r--binlog.c3
-rw-r--r--config.h.in15
-rwxr-xr-xconfigure231
-rw-r--r--configure.ac5
-rw-r--r--crypto/aes.h2
-rw-r--r--crypto/aes_altern.c2
-rw-r--r--crypto/aes_openssl.c2
-rw-r--r--crypto/bn_altern.c2
-rw-r--r--crypto/bn_openssl.c2
-rw-r--r--crypto/err_altern.c2
-rw-r--r--crypto/err_openssl.c2
-rw-r--r--crypto/md5_altern.c2
-rw-r--r--crypto/md5_openssl.c2
-rw-r--r--crypto/rand_altern.c2
-rw-r--r--crypto/rand_openssl.c2
-rw-r--r--crypto/rsa_pem_altern.c2
-rw-r--r--crypto/rsa_pem_openssl.c2
-rw-r--r--crypto/sha_altern.c2
-rw-r--r--crypto/sha_openssl.c2
-rw-r--r--queries.c2
-rw-r--r--scheme.tl2
-rw-r--r--tgl-queries.h10
-rw-r--r--tgl.h3
m---------tl-parser0
-rw-r--r--tl-parser/.gitignore8
-rw-r--r--tl-parser/LICENSE339
-rw-r--r--tl-parser/README.md1
-rw-r--r--tl-parser/portable_endian.h140
-rw-r--r--tl-parser/tl-parser-tree.h178
-rw-r--r--tl-parser/tl-parser.c3014
-rw-r--r--tl-parser/tl-parser.h206
-rw-r--r--tl-parser/tl-tl.h55
-rw-r--r--tl-parser/tlc.c165
35 files changed, 4243 insertions, 176 deletions
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index ec3f8b4..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "tl-parser"]
- path = tl-parser
- url = https://github.com/vysheng/tl-parser
diff --git a/Makefile.in b/Makefile.in
index 255efe3..c41fcdf 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -31,6 +31,13 @@ DEPENDENCE_LIST=${DEPENDENCE}
INCLUDE=-I. -I${srcdir}
CC=@CC@
+AR=@AR@
+
+# Check if -fstack-protector-strong is supported before enabling it
+SPUNSUPPORTED = $(shell $(CC) -fstack-protector-strong 2>&1 | grep -c 'stack-protector-strong')
+ifeq "$(SPUNSUPPORTED)" "0"
+ COMPILE_FLAGS += -fstack-protector-strong
+endif
.SUFFIXES:
@@ -57,7 +64,7 @@ ${TGL_OBJECTS_AUTO}: ${OBJ}/auto/%.o: ${AUTO}/%.c | create_dirs
${CC} ${INCLUDE} ${COMPILE_FLAGS} -iquote ${srcdir}/tgl -c -MP -MD -MF ${DEP}/$*.d -MQ ${OBJ}/$*.o -o $@ $<
${LIB}/libtgl.a: ${TGL_OBJECTS} ${COMMON_OBJECTS} ${TGL_OBJECTS_AUTO}
- rm -f $@ && ar ruv $@ $^
+ rm -f $@ && ${AR} ruv $@ $^
${LIB}/libtgl.so: ${TGL_OBJECTS} ${COMMON_OBJECTS} ${TGL_OBJECTS_AUTO}
${CC} -shared -o $@ $^ ${LINK_FLAGS}
diff --git a/binlog.c b/binlog.c
index 5062551..ec29982 100644
--- a/binlog.c
+++ b/binlog.c
@@ -105,7 +105,8 @@ void bl_do_set_auth_key (struct tgl_state *TLS, int num, unsigned char *buf) /*
assert (num > 0 && num <= MAX_DC_ID);
assert (TLS->DC_list[num]);
- memcpy (TLS->DC_list[num]->auth_key, buf, 256);
+ if (TLS->DC_list[num]->auth_key != (char *)buf)
+ memcpy (TLS->DC_list[num]->auth_key, buf, 256);
static unsigned char sha1_buffer[20];
TGLC_sha1 ((void *)TLS->DC_list[num]->auth_key, 256, sha1_buffer);
diff --git a/config.h.in b/config.h.in
index b242e93..ff0bf7d 100644
--- a/config.h.in
+++ b/config.h.in
@@ -39,8 +39,7 @@
/* Define to 1 if you have the <mach/mach.h> header file. */
#undef HAVE_MACH_MACH_H
-/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
- to 0 otherwise. */
+/* Define to 1 if you have the `malloc' function. */
#undef HAVE_MALLOC
/* Define to 1 if you have the <malloc.h> header file. */
@@ -64,8 +63,7 @@
/* Define to 1 if you have the <netinet/in.h> header file. */
#undef HAVE_NETINET_IN_H
-/* Define to 1 if your system has a GNU libc compatible `realloc' function,
- and to 0 otherwise. */
+/* Define to 1 if you have the `realloc' function. */
#undef HAVE_REALLOC
/* Define to 1 if you have the `select' function. */
@@ -113,9 +111,6 @@
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
-/* Define to 1 if the system has the `__builtin_bswap32' built-in function */
-#undef HAVE___BUILTIN_BSWAP32
-
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
@@ -153,12 +148,6 @@
#undef inline
#endif
-/* Define to rpl_malloc if the replacement function should be used. */
-#undef malloc
-
-/* Define to rpl_realloc if the replacement function should be used. */
-#undef realloc
-
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t
diff --git a/configure b/configure
index afc0c36..701a5d6 100755
--- a/configure
+++ b/configure
@@ -620,9 +620,9 @@ ac_includes_default="\
#endif"
ac_subst_vars='LTLIBOBJS
+LIBOBJS
EXTRA_OBJECTS
EXTRA_LIBS
-LIBOBJS
EGREP
GREP
CPP
@@ -630,6 +630,7 @@ OPENSSL_LDFLAGS
OPENSSL_LIBS
OPENSSL_INCLUDES
PKG_CONFIG
+AR
OBJEXT
EXEEXT
ac_ct_CC
@@ -3099,6 +3100,98 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_AR" = x; then
+ AR="as_fn_error $? "No ar found. Huh?" "$LINENO" 5"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+else
+ AR="$ac_cv_prog_AR"
+fi
+
# BSD locations for headers and libraries from packages, Linux locations for self-compiled stuff.
CPPFLAGS="$CPPFLAGS -I/usr/local/include"
@@ -4348,141 +4441,7 @@ esac
# Checks for library functions.
-for ac_header in stdlib.h
-do :
- ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_stdlib_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_STDLIB_H 1
-_ACEOF
-
-fi
-
-done
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5
-$as_echo_n "checking for GNU libc compatible malloc... " >&6; }
-if ${ac_cv_func_malloc_0_nonnull+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test "$cross_compiling" = yes; then :
- ac_cv_func_malloc_0_nonnull=no
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#if defined STDC_HEADERS || defined HAVE_STDLIB_H
-# include <stdlib.h>
-#else
-char *malloc ();
-#endif
-
-int
-main ()
-{
-return ! malloc (0);
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- ac_cv_func_malloc_0_nonnull=yes
-else
- ac_cv_func_malloc_0_nonnull=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5
-$as_echo "$ac_cv_func_malloc_0_nonnull" >&6; }
-if test $ac_cv_func_malloc_0_nonnull = yes; then :
-
-$as_echo "#define HAVE_MALLOC 1" >>confdefs.h
-
-else
- $as_echo "#define HAVE_MALLOC 0" >>confdefs.h
-
- case " $LIBOBJS " in
- *" malloc.$ac_objext "* ) ;;
- *) LIBOBJS="$LIBOBJS malloc.$ac_objext"
- ;;
-esac
-
-
-$as_echo "#define malloc rpl_malloc" >>confdefs.h
-
-fi
-
-
-for ac_header in stdlib.h
-do :
- ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_stdlib_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_STDLIB_H 1
-_ACEOF
-
-fi
-
-done
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5
-$as_echo_n "checking for GNU libc compatible realloc... " >&6; }
-if ${ac_cv_func_realloc_0_nonnull+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test "$cross_compiling" = yes; then :
- ac_cv_func_realloc_0_nonnull=no
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#if defined STDC_HEADERS || defined HAVE_STDLIB_H
-# include <stdlib.h>
-#else
-char *realloc ();
-#endif
-
-int
-main ()
-{
-return ! realloc (0, 0);
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- ac_cv_func_realloc_0_nonnull=yes
-else
- ac_cv_func_realloc_0_nonnull=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5
-$as_echo "$ac_cv_func_realloc_0_nonnull" >&6; }
-if test $ac_cv_func_realloc_0_nonnull = yes; then :
-
-$as_echo "#define HAVE_REALLOC 1" >>confdefs.h
-
-else
- $as_echo "#define HAVE_REALLOC 0" >>confdefs.h
-
- case " $LIBOBJS " in
- *" realloc.$ac_objext "* ) ;;
- *) LIBOBJS="$LIBOBJS realloc.$ac_objext"
- ;;
-esac
-
-
-$as_echo "#define realloc rpl_realloc" >>confdefs.h
-
-fi
-
-
-for ac_func in alarm endpwent memset memmove mkdir select socket strdup strndup uname
+for ac_func in alarm endpwent malloc memset memmove mkdir realloc select socket strdup strndup uname
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/configure.ac b/configure.ac
index dab47aa..416c550 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,6 +8,7 @@ m4_include([m4_ax_check_zlib.m4])
# Checks for programs.
AC_PROG_CC
+AC_CHECK_TOOL(AR, ar, [AC_MSG_ERROR([No ar found. Huh?])])
# BSD locations for headers and libraries from packages, Linux locations for self-compiled stuff.
CPPFLAGS="$CPPFLAGS -I/usr/local/include"
@@ -83,9 +84,7 @@ AC_TYPE_UID_T
AC_C_INLINE
# Checks for library functions.
-AC_FUNC_MALLOC
-AC_FUNC_REALLOC
-AC_CHECK_FUNCS([alarm endpwent memset memmove mkdir select socket strdup strndup uname])
+AC_CHECK_FUNCS([alarm endpwent malloc memset memmove mkdir realloc select socket strdup strndup uname])
AC_SUBST(EXTRA_LIBS)
AC_SUBST(EXTRA_OBJECTS)
diff --git a/crypto/aes.h b/crypto/aes.h
index f0c61aa..2fddc01 100644
--- a/crypto/aes.h
+++ b/crypto/aes.h
@@ -23,7 +23,7 @@
#include <stddef.h> /* size_t */
-#include "../config.h"
+#include "config.h"
typedef struct TGLC_aes_key {
char _dummy[
diff --git a/crypto/aes_altern.c b/crypto/aes_altern.c
index 9f42042..e446065 100644
--- a/crypto/aes_altern.c
+++ b/crypto/aes_altern.c
@@ -18,7 +18,7 @@
Copyright Ben Wiederhake 2015
*/
-#include "../config.h"
+#include "config.h"
#ifdef TGL_AVOID_OPENSSL
diff --git a/crypto/aes_openssl.c b/crypto/aes_openssl.c
index c6c1840..495099e 100644
--- a/crypto/aes_openssl.c
+++ b/crypto/aes_openssl.c
@@ -18,7 +18,7 @@
Copyright Ben Wiederhake 2015
*/
-#include "../config.h"
+#include "config.h"
#ifndef TGL_AVOID_OPENSSL
diff --git a/crypto/bn_altern.c b/crypto/bn_altern.c
index e1ae412..73dae46 100644
--- a/crypto/bn_altern.c
+++ b/crypto/bn_altern.c
@@ -18,7 +18,7 @@
Copyright Ben Wiederhake 2015
*/
-#include "../config.h"
+#include "config.h"
#ifdef TGL_AVOID_OPENSSL
diff --git a/crypto/bn_openssl.c b/crypto/bn_openssl.c
index 73f3c69..c5bd374 100644
--- a/crypto/bn_openssl.c
+++ b/crypto/bn_openssl.c
@@ -18,7 +18,7 @@
Copyright Ben Wiederhake 2015
*/
-#include "../config.h"
+#include "config.h"
#ifndef TGL_AVOID_OPENSSL
diff --git a/crypto/err_altern.c b/crypto/err_altern.c
index 610e205..d8ade14 100644
--- a/crypto/err_altern.c
+++ b/crypto/err_altern.c
@@ -18,7 +18,7 @@
Copyright Ben Wiederhake 2015
*/
-#include "../config.h"
+#include "config.h"
#ifdef TGL_AVOID_OPENSSL
diff --git a/crypto/err_openssl.c b/crypto/err_openssl.c
index 2b23cb0..b0b2271 100644
--- a/crypto/err_openssl.c
+++ b/crypto/err_openssl.c
@@ -18,7 +18,7 @@
Copyright Ben Wiederhake 2015
*/
-#include "../config.h"
+#include "config.h"
#ifndef TGL_AVOID_OPENSSL
diff --git a/crypto/md5_altern.c b/crypto/md5_altern.c
index 30c3018..0c3ae86 100644
--- a/crypto/md5_altern.c
+++ b/crypto/md5_altern.c
@@ -18,7 +18,7 @@
Copyright Ben Wiederhake 2015
*/
-#include "../config.h"
+#include "config.h"
#ifdef TGL_AVOID_OPENSSL
diff --git a/crypto/md5_openssl.c b/crypto/md5_openssl.c
index 1ba3c9e..8c82235 100644
--- a/crypto/md5_openssl.c
+++ b/crypto/md5_openssl.c
@@ -18,7 +18,7 @@
Copyright Ben Wiederhake 2015
*/
-#include "../config.h"
+#include "config.h"
#ifndef TGL_AVOID_OPENSSL
diff --git a/crypto/rand_altern.c b/crypto/rand_altern.c
index aca536f..8c201b1 100644
--- a/crypto/rand_altern.c
+++ b/crypto/rand_altern.c
@@ -18,7 +18,7 @@
Copyright Ben Wiederhake 2015
*/
-#include "../config.h"
+#include "config.h"
#ifdef TGL_AVOID_OPENSSL
diff --git a/crypto/rand_openssl.c b/crypto/rand_openssl.c
index bb2d504..31f455b 100644
--- a/crypto/rand_openssl.c
+++ b/crypto/rand_openssl.c
@@ -18,7 +18,7 @@
Copyright Ben Wiederhake 2015
*/
-#include "../config.h"
+#include "config.h"
#ifndef TGL_AVOID_OPENSSL
diff --git a/crypto/rsa_pem_altern.c b/crypto/rsa_pem_altern.c
index ad5aecb..4bfa056 100644
--- a/crypto/rsa_pem_altern.c
+++ b/crypto/rsa_pem_altern.c
@@ -18,7 +18,7 @@
Copyright Ben Wiederhake 2015
*/
-#include "../config.h"
+#include "config.h"
#ifdef TGL_AVOID_OPENSSL
diff --git a/crypto/rsa_pem_openssl.c b/crypto/rsa_pem_openssl.c
index 06b630f..fe5cd9c 100644
--- a/crypto/rsa_pem_openssl.c
+++ b/crypto/rsa_pem_openssl.c
@@ -18,7 +18,7 @@
Copyright Ben Wiederhake 2015
*/
-#include "../config.h"
+#include "config.h"
#ifndef TGL_AVOID_OPENSSL
diff --git a/crypto/sha_altern.c b/crypto/sha_altern.c
index 7615cfd..c48a60c 100644
--- a/crypto/sha_altern.c
+++ b/crypto/sha_altern.c
@@ -18,7 +18,7 @@
Copyright Ben Wiederhake 2015
*/
-#include "../config.h"
+#include "config.h"
#ifdef TGL_AVOID_OPENSSL
diff --git a/crypto/sha_openssl.c b/crypto/sha_openssl.c
index eb40467..6f3390a 100644
--- a/crypto/sha_openssl.c
+++ b/crypto/sha_openssl.c
@@ -18,7 +18,7 @@
Copyright Ben Wiederhake 2015
*/
-#include "../config.h"
+#include "config.h"
#ifndef TGL_AVOID_OPENSSL
diff --git a/queries.c b/queries.c
index cc11b5e..bbebecd 100644
--- a/queries.c
+++ b/queries.c
@@ -314,7 +314,7 @@ int tglq_query_error (struct tgl_state *TLS, long long id) {
char *error = fetch_str (error_len);
struct query *q = tglq_query_get (TLS, id);
if (!q) {
- vlogprintf (E_WARNING, "error for query '%s' #%" INT64_PRINTF_MODIFIER "d: #%d :%.*s\n", q->methods->name, id, error_code, error_len, error);
+ vlogprintf (E_WARNING, "error for query ?! #%" INT64_PRINTF_MODIFIER "d: #%d :%.*s\n", id, error_code, error_len, error);
vlogprintf (E_WARNING, "No such query\n");
} else {
if (!(q->flags & QUERY_ACK_RECEIVED)) {
diff --git a/scheme.tl b/scheme.tl
index 6411438..2d89fbc 100644
--- a/scheme.tl
+++ b/scheme.tl
@@ -451,7 +451,7 @@ chatInviteEmpty#69df3769 = ExportedChatInvite;
chatInviteExported#fc2e05bc link:string = ExportedChatInvite;
chatInviteAlready#5a686d7c chat:Chat = ChatInvite;
-chatInvite#93e99b60 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string = ChatInvite;
+chatInvite#93e99b60 flags:# channel:flags.0?true broadcast:flags.1?true public_:flags.2?true megagroup:flags.3?true title:string = ChatInvite;
inputStickerSetEmpty#ffb62b95 = InputStickerSet;
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
diff --git a/tgl-queries.h b/tgl-queries.h
index 614dc6d..0fdd26b 100644
--- a/tgl-queries.h
+++ b/tgl-queries.h
@@ -3,6 +3,10 @@
#include "tgl.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void tgl_do_get_terms_of_service (struct tgl_state *TLS, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *ans), void *callback_extra);
/* {{{ WORK WITH ACCOUNT */
@@ -121,7 +125,7 @@ void tgl_do_export_chat_link (struct tgl_state *TLS, tgl_peer_id_t id, void (*ca
// joins to secret chat by link (or hash of this link)
void tgl_do_import_chat_link (struct tgl_state *TLS, const char *link, int link_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra);
-// upgrades chat to channel.
+// upgrades chat to channel.
void tgl_do_upgrade_group (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra);
/* }}} */
@@ -299,4 +303,8 @@ char *tglf_extf_fetch (struct tgl_state *TLS, struct paramed_type *T);
void tgl_do_start_bot (struct tgl_state *TLS, tgl_peer_id_t bot, tgl_peer_id_t chat, const char *str, int str_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra);
/* }}} */
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/tgl.h b/tgl.h
index d924f7e..70dab53 100644
--- a/tgl.h
+++ b/tgl.h
@@ -210,7 +210,7 @@ struct tgl_state {
long long rsa_key_fingerprint[TGL_MAX_RSA_KEYS_NUM];
int rsa_key_num;
- TGLC_bn_ctx *TGLC_bn_ctx;
+ struct TGLC_bn_ctx *TGLC_bn_ctx;
struct tgl_allocator *allocator;
@@ -387,6 +387,7 @@ void tgl_disable_link_preview (struct tgl_state *TLS);
void tgl_do_lookup_state (struct tgl_state *TLS);
long long tgl_get_allocated_bytes (void);
+
#ifdef __cplusplus
}
#endif
diff --git a/tl-parser b/tl-parser
deleted file mode 160000
-Subproject 36bf1902ff3476c75d0b1f42b34a91e944123b3
diff --git a/tl-parser/.gitignore b/tl-parser/.gitignore
new file mode 100644
index 0000000..a49c101
--- /dev/null
+++ b/tl-parser/.gitignore
@@ -0,0 +1,8 @@
+Makefile
+config.h
+dep
+objs
+bin
+autom4te.cache
+config.log
+config.status
diff --git a/tl-parser/LICENSE b/tl-parser/LICENSE
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/tl-parser/LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/tl-parser/README.md b/tl-parser/README.md
new file mode 100644
index 0000000..ce211a2
--- /dev/null
+++ b/tl-parser/README.md
@@ -0,0 +1 @@
+Parse tl scheme to tlo file. Formely part of telegram-cli
diff --git a/tl-parser/portable_endian.h b/tl-parser/portable_endian.h
new file mode 100644
index 0000000..c7720ae
--- /dev/null
+++ b/tl-parser/portable_endian.h
@@ -0,0 +1,140 @@
+// "License": Public Domain
+// I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like.
+// In case there are jurisdictions that don't support putting things in the public domain you can also consider it to
+// be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it
+// an example on how to get the endian conversion functions on different platforms.
+
+/* Originally cloned from https://gist.github.com/PkmX/63dd23f28ba885be53a5
+ * Commit was: 1eca2ab34f2301b9641aa73d1016b951fff3fc39
+ * Re-published at https://github.com/BenWiederhake/portable-endian.h to provide a means to submit patches and report issues. */
+
+#ifndef PORTABLE_ENDIAN_H__
+#define PORTABLE_ENDIAN_H__
+
+#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)
+
+# define __WINDOWS__
+
+#endif
+
+#if defined(__linux__) || defined(__CYGWIN__)
+
+# include <endian.h>
+
+#elif defined(__APPLE__)
+
+# include <libkern/OSByteOrder.h>
+
+# define htobe16(x) OSSwapHostToBigInt16(x)
+# define htole16(x) OSSwapHostToLittleInt16(x)
+# define be16toh(x) OSSwapBigToHostInt16(x)
+# define le16toh(x) OSSwapLittleToHostInt16(x)
+
+# define htobe32(x) OSSwapHostToBigInt32(x)
+# define htole32(x) OSSwapHostToLittleInt32(x)
+# define be32toh(x) OSSwapBigToHostInt32(x)
+# define le32toh(x) OSSwapLittleToHostInt32(x)
+
+# define htobe64(x) OSSwapHostToBigInt64(x)
+# define htole64(x) OSSwapHostToLittleInt64(x)
+# define be64toh(x) OSSwapBigToHostInt64(x)
+# define le64toh(x) OSSwapLittleToHostInt64(x)
+
+# define __BYTE_ORDER BYTE_ORDER
+# define __BIG_ENDIAN BIG_ENDIAN
+# define __LITTLE_ENDIAN LITTLE_ENDIAN
+# define __PDP_ENDIAN PDP_ENDIAN
+
+#elif defined(__OpenBSD__) || defined(__FreeBSD__)
+
+# include <sys/endian.h>
+
+#elif defined(__sun)
+
+# include <sys/byteorder.h>
+# define htobe16(x) BE_16(x)
+# define htole16(x) LE_16(x)
+# define be16toh(x) BE_IN16(x)
+# define le16toh(x) LE_IN16(x)
+
+# define htobe32(x) BE_32(x)
+# define htole32(x) LE_32(x)
+# define be32toh(x) BE_IN32(x)
+# define le32toh(x) LE_IN32(x)
+
+# define htobe64(x) BE_64(x)
+# define htole64(x) LE_64(x)
+# define be64toh(x) BE_IN64(x)
+# define le64toh(x) LE_IN64(x)
+
+#elif defined(__NetBSD__) || defined(__DragonFly__)
+
+# include <sys/endian.h>
+
+# define be16toh(x) betoh16(x)
+# define le16toh(x) letoh16(x)
+
+# define be32toh(x) betoh32(x)
+# define le32toh(x) letoh32(x)
+
+# define be64toh(x) betoh64(x)
+# define le64toh(x) letoh64(x)
+
+#elif defined(__WINDOWS__)
+
+# include <winsock2.h>
+# include <sys/param.h>
+
+# if BYTE_ORDER == LITTLE_ENDIAN
+
+# define htobe16(x) htons(x)
+# define htole16(x) (x)
+# define be16toh(x) ntohs(x)
+# define le16toh(x) (x)
+
+# define htobe32(x) htonl(x)
+# define htole32(x) (x)
+# define be32toh(x) ntohl(x)
+# define le32toh(x) (x)
+
+# define htobe64(x) __builtin_bswap64(x)
+# define htole64(x) (x)
+# define be64toh(x) __builtin_bswap64(x)
+# define le64toh(x) (x)
+
+# elif BYTE_ORDER == BIG_ENDIAN
+
+ /* that would be xbox 360 */
+# define htobe16(x) (x)
+# define htole16(x) __builtin_bswap16(x)
+# define be16toh(x) (x)
+# define le16toh(x) __builtin_bswap16(x)
+
+# define htobe32(x) (x)
+# define htole32(x) __builtin_bswap32(x)
+# define be32toh(x) (x)
+# define le32toh(x) __builtin_bswap32(x)
+
+# define htobe64(x) (x)
+# define htole64(x) __builtin_bswap64(x)
+# define be64toh(x) (x)
+# define le64toh(x) __builtin_bswap64(x)
+
+# else
+
+# error byte order not supported
+
+# endif
+
+# define __BYTE_ORDER BYTE_ORDER
+# define __BIG_ENDIAN BIG_ENDIAN
+# define __LITTLE_ENDIAN LITTLE_ENDIAN
+# define __PDP_ENDIAN PDP_ENDIAN
+
+#else
+
+# error platform not supported
+
+#endif
+
+#endif
diff --git a/tl-parser/tl-parser-tree.h b/tl-parser/tl-parser-tree.h
new file mode 100644
index 0000000..fba7c67
--- /dev/null
+++ b/tl-parser/tl-parser-tree.h
@@ -0,0 +1,178 @@
+/*
+ This file is part of tgl-library
+
+ 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
+
+ Copyright Vitaly Valtman 2013-2014
+*/
+#ifndef __TREE_H__
+#define __TREE_H__
+#include <stdio.h>
+
+#include <memory.h>
+#include <assert.h>
+
+#pragma pack(push,4)
+#define DEFINE_TREE(X_NAME, X_TYPE, X_CMP, X_UNSET) \
+struct tree_ ## X_NAME { \
+ struct tree_ ## X_NAME *left, *right;\
+ X_TYPE x;\
+ int y;\
+};\
+\
+static struct tree_ ## X_NAME *new_tree_node_ ## X_NAME (X_TYPE x, int y) {\
+ struct tree_ ## X_NAME *T = malloc (sizeof (*T));\
+ T->x = x;\
+ T->y = y;\
+ T->left = T->right = 0;\
+ return T;\
+}\
+\
+static void delete_tree_node_ ## X_NAME (struct tree_ ## X_NAME *T) {\
+ free (T);\
+}\
+\
+static void tree_split_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, struct tree_ ## X_NAME **L, struct tree_ ## X_NAME **R) {\
+ if (!T) {\
+ *L = *R = 0;\
+ } else {\
+ int c = X_CMP (x, T->x);\
+ if (c < 0) {\
+ tree_split_ ## X_NAME (T->left, x, L, &T->left);\
+ *R = T;\
+ } else {\
+ tree_split_ ## X_NAME (T->right, x, &T->right, R);\
+ *L = T;\
+ }\
+ }\
+}\
+\
+static struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) __attribute__ ((warn_unused_result,unused));\
+static struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) {\
+ if (!T) {\
+ return new_tree_node_ ## X_NAME (x, y);\
+ } else {\
+ if (y > T->y) {\
+ struct tree_ ## X_NAME *N = new_tree_node_ ## X_NAME (x, y);\
+ tree_split_ ## X_NAME (T, x, &N->left, &N->right);\
+ return N;\
+ } else {\
+ int c = X_CMP (x, T->x);\
+ assert (c);\
+ if (c < 0) { \
+ T->left = tree_insert_ ## X_NAME (T->left, x, y);\
+ } else { \
+ T->right = tree_insert_ ## X_NAME (T->right, x, y);\
+ } \
+ return T; \
+ }\
+ }\
+}\
+\
+static struct tree_ ## X_NAME *tree_merge_ ## X_NAME (struct tree_ ## X_NAME *L, struct tree_ ## X_NAME *R) {\
+ if (!L || !R) {\
+ return L ? L : R;\
+ } else {\
+ if (L->y > R->y) {\
+ L->right = tree_merge_ ## X_NAME (L->right, R);\
+ return L;\
+ } else {\
+ R->left = tree_merge_ ## X_NAME (L, R->left);\
+ return R;\
+ }\
+ }\
+}\
+\
+static struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((warn_unused_result,unused));\
+static struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\
+ assert (T);\
+ int c = X_CMP (x, T->x);\
+ if (!c) {\
+ struct tree_ ## X_NAME *N = tree_merge_ ## X_NAME (T->left, T->right);\
+ delete_tree_node_ ## X_NAME (T);\
+ return N;\
+ } else {\
+ if (c < 0) { \
+ T->left = tree_delete_ ## X_NAME (T->left, x); \
+ } else { \
+ T->right = tree_delete_ ## X_NAME (T->right, x); \
+ } \
+ return T; \
+ }\
+}\
+\
+static X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *t) __attribute__ ((unused));\
+static X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *T) {\
+ if (!T) { return X_UNSET; } \
+ while (T->left) { T = T->left; }\
+ return T->x; \
+} \
+\
+static X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((unused));\
+static X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\
+ int c;\
+ while (T && (c = X_CMP (x, T->x))) {\
+ T = (c < 0 ? T->left : T->right);\
+ }\
+ return T ? T->x : X_UNSET;\
+}\
+\
+static void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) __attribute__ ((unused));\
+static void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) {\
+ if (!T) { return; } \
+ tree_act_ ## X_NAME (T->left, act); \
+ act (T->x); \
+ tree_act_ ## X_NAME (T->right, act); \
+}\
+\
+static void tree_act_ex_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE, void *), void *extra) __attribute__ ((unused));\
+static void tree_act_ex_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE, void *), void *extra) {\
+ if (!T) { return; } \
+ tree_act_ex_ ## X_NAME (T->left, act, extra); \
+ act (T->x, extra); \
+ tree_act_ex_ ## X_NAME (T->right, act, extra); \
+}\
+\
+static int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\
+static int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) { \
+ if (!T) { return 0; }\
+ return 1 + tree_count_ ## X_NAME (T->left) + tree_count_ ## X_NAME (T->right); \
+}\
+static void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\
+static void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) { \
+ if (!T) { return; }\
+ if (T->left) { \
+ assert (T->left->y <= T->y);\
+ assert (X_CMP (T->left->x, T->x) < 0); \
+ }\
+ if (T->right) { \
+ assert (T->right->y <= T->y);\
+ assert (X_CMP (T->right->x, T->x) > 0); \
+ }\
+ tree_check_ ## X_NAME (T->left); \
+ tree_check_ ## X_NAME (T->right); \
+}\
+static struct tree_ ## X_NAME *tree_clear_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\
+static struct tree_ ## X_NAME *tree_clear_ ## X_NAME (struct tree_ ## X_NAME *T) { \
+ if (!T) { return 0; }\
+ tree_clear_ ## X_NAME (T->left); \
+ tree_clear_ ## X_NAME (T->right); \
+ delete_tree_node_ ## X_NAME (T); \
+ return 0; \
+} \
+
+#define int_cmp(a,b) ((a) - (b))
+#pragma pack(pop)
+#endif
diff --git a/tl-parser/tl-parser.c b/tl-parser/tl-parser.c
new file mode 100644
index 0000000..c2fd179
--- /dev/null
+++ b/tl-parser/tl-parser.c
@@ -0,0 +1,3014 @@
+/*
+ This file is part of tl-parser
+
+ tl-parser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ tl-parser 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this tl-parser. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright Vitaly Valtman 2014
+
+ It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/)
+ Copyright 2012-2013 Vkontakte Ltd
+ 2012-2013 Vitaliy Valtman
+
+*/
+
+#define _FILE_OFFSET_BITS 64
+#include "config.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+#include <zlib.h>
+#include "portable_endian.h"
+#include "tl-parser-tree.h"
+#include "tl-parser.h"
+#include "tl-tl.h"
+#include "config.h"
+
+extern int verbosity;
+extern int schema_version;
+extern int output_expressions;
+
+
+int total_types_num;
+int total_constructors_num;
+int total_functions_num;
+
+
+/*char *tstrdup (const char *s) {
+ assert (s);
+ char *r = talloc (strlen (s) + 1);
+ memcpy (r, s, strlen (s) + 1);
+ return r;
+}*/
+
+#define talloc(a) malloc(a)
+#define tfree(a,b) free (a)
+#define talloc0(a) calloc(a,1)
+#define tstrdup(a) strdup(a)
+
+typedef char error_int_must_be_4_byte[(sizeof (int) == 4) ? 1 : -1];
+typedef char error_long_long_must_be_8_byte[(sizeof (long long) == 8) ? 1 : -1];
+
+char curch;
+struct parse parse;
+
+struct tree *tree;
+
+struct tree *tree_alloc (void) {
+ struct tree *T = talloc (sizeof (*T));
+ assert (T);
+ memset (T, 0, sizeof (*T));
+ return T;
+}
+
+#define CRC32_INITIAL crc32 (0, 0, 0)
+
+void tree_add_child (struct tree *P, struct tree *C) {
+ if (P->nc == P->size) {
+ void **t = talloc (sizeof (void *) * (++P->size));
+ memcpy (t, P->c, sizeof (void *) * (P->size - 1));
+ if (P->c) {
+ tfree (P->c, sizeof (void *) * (P->size - 1));
+ }
+ P->c = (void *)t;
+ assert (P->c);
+ }
+ P->c[P->nc ++] = C;
+}
+
+void tree_delete (struct tree *T) {
+ assert (T);
+ int i;
+ for (i = 0; i < T->nc; i++) {
+ assert (T->c[i]);
+ tree_delete (T->c[i]);
+ }
+ if (T->c) {
+ tfree (T->c, sizeof (void *) * T->nc);
+ }
+ tfree (T, sizeof (*T));
+}
+
+void tree_del_child (struct tree *P) {
+ assert (P->nc);
+ tree_delete (P->c[--P->nc]);
+}
+
+
+char nextch (void) {
+ if (parse.pos < parse.len - 1) {
+ curch = parse.text[++parse.pos];
+ } else {
+ curch = 0;
+ }
+ if (curch == 10) {
+ parse.line ++;
+ parse.line_pos = 0;
+ } else {
+ if (curch) {
+ parse.line_pos ++;
+ }
+ }
+ return curch;
+}
+
+
+struct parse save_parse (void) {
+ return parse;
+}
+
+void load_parse (struct parse _parse) {
+ parse = _parse;
+ curch = parse.pos > parse.len ? 0: parse.text[parse.pos] ;
+}
+
+int is_whitespace (char c) {
+ return (c <= 32);
+}
+
+int is_uletter (char c) {
+ return (c >= 'A' && c <= 'Z');
+}
+
+int is_lletter (char c) {
+ return (c >= 'a' && c <= 'z');
+}
+
+int is_letter (char c) {
+ return is_uletter (c) || is_lletter (c);
+}
+
+int is_digit (char c) {
+ return (c >= '0' && c <= '9');
+}
+
+int is_hexdigit (char c) {
+ return is_digit (c) || (c >= 'a' && c <= 'f');
+}
+
+int is_ident_char (char c) {
+ return is_digit (c) || is_letter (c) || c == '_';
+}
+
+int last_error_pos;
+int last_error_line;
+int last_error_line_pos;
+char *last_error;
+
+void parse_error (const char *e) {
+ if (parse.pos > last_error_pos) {
+ last_error_pos = parse.pos;
+ last_error_line = parse.line;
+ last_error_line_pos = parse.line_pos;
+ if (last_error) {
+ tfree (last_error, strlen (last_error) + 1);
+ }
+ last_error = tstrdup (e);
+ }
+}
+
+void tl_print_parse_error (void) {
+ fprintf (stderr, "Error near line %d pos %d: `%s`\n", last_error_line + 1, last_error_line_pos + 1, last_error);
+}
+
+char *parse_lex (void) {
+ while (1) {
+ while (curch && is_whitespace (curch)) { nextch (); }
+ if (curch == '/' && nextch () == '/') {
+ while (nextch () != 10);
+ nextch ();
+ } else {
+ break;
+ }
+ }
+ if (!curch) {
+ parse.lex.len = 0;
+ parse.lex.type = lex_eof;
+ return (parse.lex.ptr = 0);
+ }
+ char *p = parse.text + parse.pos;
+ parse.lex.flags = 0;
+ switch (curch) {
+ case '-':
+ if (nextch () != '-' || nextch () != '-') {
+ parse_error ("Can not parse triple minus");
+ parse.lex.type = lex_error;
+ return (parse.lex.ptr = (void *)-1);
+ } else {
+ parse.lex.len = 3;
+ parse.lex.type = lex_triple_minus;
+ nextch ();
+ return (parse.lex.ptr = p);
+ }
+ case ':':
+ case ';':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '=':
+ case '#':
+ case '?':
+ case '%':
+ case '<':
+ case '>':
+ case '+':
+ case ',':
+ case '*':
+ case '_':
+ case '!':
+ case '.':
+ nextch ();
+ parse.lex.len = 1;
+ parse.lex.type = lex_char;
+ return (parse.lex.ptr = p);
+ case 'a'...'z':
+ case 'A'...'Z':
+ parse.lex.flags = 0;
+ if (is_uletter (curch)) {
+ while (is_ident_char (nextch ()));
+ parse.lex.len = parse.text + parse.pos - p;
+ parse.lex.ptr = p;
+ if (parse.lex.len == 5 && !memcmp (parse.lex.ptr, "Final", 5)) {
+ parse.lex.type = lex_final;
+ } else if (parse.lex.len == 3 && !memcmp (parse.lex.ptr, "New", 3)) {
+ parse.lex.type = lex_new;
+ } else if (parse.lex.len == 5 && !memcmp (parse.lex.ptr, "Empty", 5)) {
+ parse.lex.type = lex_empty;
+ } else {
+ parse.lex.type = lex_uc_ident;
+ }
+ return (parse.lex.ptr = p);
+ }
+ while (is_ident_char (nextch ()));
+ if (curch == '.' && !is_letter (parse.text[parse.pos + 1])) {
+ parse.lex.len = parse.text + parse.pos - p;
+ parse.lex.type = lex_lc_ident;
+ return (parse.lex.ptr = p);
+ }
+ if (curch == '.') {
+ parse.lex.flags |= 1;
+ nextch ();
+ if (is_uletter (curch)) {
+ while (is_ident_char (nextch ()));
+ parse.lex.len = parse.text + parse.pos - p;
+ parse.lex.type = lex_uc_ident;
+ return (parse.lex.ptr = p);
+ }
+ if (is_lletter (curch)) {
+ while (is_ident_char (nextch ()));
+ } else {
+ parse_error ("Expected letter");
+ parse.lex.type = lex_error;
+ return (parse.lex.ptr = (void *)-1);
+ }
+ }
+ if (curch == '#') {
+ parse.lex.flags |= 2;
+ int i;
+ int ok = 1;
+ for (i = 0; i < 8; i++) {
+ if (!is_hexdigit (nextch())) {
+ if (curch == ' ' && i >= 5) {
+ ok = 2;
+ break;
+ } else {
+ parse_error ("Hex digit expected");
+ parse.lex.type = lex_error;
+ return (parse.lex.ptr = (void *)-1);
+ }
+ }
+ }
+ if (ok == 1) {
+ nextch ();
+ }
+ }
+ parse.lex.len = parse.text + parse.pos - p;
+ parse.lex.type = lex_lc_ident;
+ return (parse.lex.ptr = p);
+ case '0'...'9':
+ while (is_digit (nextch ()));
+ parse.lex.len = parse.text + parse.pos - p;
+ parse.lex.type = lex_num;
+ return (parse.lex.ptr = p);
+ default:
+ parse_error ("Unknown lexem");
+ parse.lex.type = lex_error;
+ return (parse.lex.ptr = (void *)-1);
+ }
+
+}
+
+int expect (char *s) {
+ if (!parse.lex.ptr || parse.lex.ptr == (void *)-1 || parse.lex.type == lex_error || parse.lex.type == lex_none || parse.lex.len != (int)strlen (s) || memcmp (s, parse.lex.ptr, parse.lex.len)) {
+ static char buf[1000];
+ sprintf (buf, "Expected %s", s);
+ parse_error (buf);
+ return -1;
+ } else {
+ parse_lex ();
+ }
+ return 1;
+}
+
+struct parse *tl_init_parse_file (const char *fname) {
+ int fd = open (fname, O_RDONLY);
+ if (fd < 0) {
+ fprintf (stderr, "Error %m\n");
+ assert (0);
+ return 0;
+ }
+ long long size = lseek (fd, 0, SEEK_END);
+ if (size <= 0) {
+ fprintf (stderr, "size is %lld. Too small.\n", size);
+ return 0;
+ }
+ static struct parse save;
+ save.text = talloc (size);
+ lseek (fd, 0, SEEK_SET);
+ save.len = read (fd, save.text, size);
+ assert (save.len == size);
+ save.pos = 0;
+ save.line = 0;
+ save.line_pos = 0;
+ save.lex.ptr = save.text;
+ save.lex.len = 0;
+ save.lex.type = lex_none;
+ return &save;
+}
+
+#define PARSE_INIT(_type) struct parse save = save_parse (); struct tree *T = tree_alloc (); T->type = (_type); T->lex_line = parse.line; T->lex_line_pos = parse.line_pos; struct tree *S __attribute__ ((unused));
+#define PARSE_FAIL load_parse (save); tree_delete (T); return 0;
+#define PARSE_OK return T;
+#define PARSE_TRY_PES(x) if (!(S = x ())) { PARSE_FAIL; } { tree_add_child (T, S); }
+#define PARSE_TRY_OPT(x) if ((S = x ())) { tree_add_child (T, S); PARSE_OK }
+#define PARSE_TRY(x) S = x ();
+#define PARSE_ADD(_type) S = tree_alloc (); S->type = _type; tree_add_child (T, S);
+#define EXPECT(s) if (expect (s) < 0) { PARSE_FAIL; }
+#define LEX_CHAR(c) (parse.lex.type == lex_char && *parse.lex.ptr == c)
+struct tree *parse_args (void);
+struct tree *parse_expr (void);
+
+struct tree *parse_boxed_type_ident (void) {
+ PARSE_INIT (type_boxed_type_ident);
+ if (parse.lex.type != lex_uc_ident) {
+ parse_error ("Can not parse boxed type");
+ PARSE_FAIL;
+ } else {
+ T->text = parse.lex.ptr;
+ T->len = parse.lex.len;
+ T->flags = parse.lex.flags;
+ parse_lex ();
+ PARSE_OK;
+ }
+}
+
+struct tree *parse_full_combinator_id (void) {
+ PARSE_INIT (type_full_combinator_id);
+ if (parse.lex.type == lex_lc_ident || LEX_CHAR('_')) {
+ T->text = parse.lex.ptr;
+ T->len = parse.lex.len;
+ T->flags = parse.lex.flags;
+ parse_lex ();
+ PARSE_OK;
+ } else {
+ parse_error ("Can not parse full combinator id");
+ PARSE_FAIL;
+ }
+}
+
+struct tree *parse_combinator_id (void) {
+ PARSE_INIT (type_combinator_id);
+ if (parse.lex.type == lex_lc_ident && !(parse.lex.flags & 2)) {
+ T->text = parse.lex.ptr;
+ T->len = parse.lex.len;
+ T->flags = parse.lex.flags;
+ parse_lex ();
+ PARSE_OK;
+ } else {
+ parse_error ("Can not parse combinator id");
+ PARSE_FAIL;
+ }
+}
+
+struct tree *parse_var_ident (void) {
+ PARSE_INIT (type_var_ident);
+ if ((parse.lex.type == lex_lc_ident || parse.lex.type == lex_uc_ident) && !(parse.lex.flags & 3)) {
+ T->text = parse.lex.ptr;
+ T->len = parse.lex.len;
+ T->flags = parse.lex.flags;
+ parse_lex ();
+ PARSE_OK;
+ } else {
+ parse_error ("Can not parse var ident");
+ PARSE_FAIL;
+ }
+}
+
+struct tree *parse_var_ident_opt (void) {
+ PARSE_INIT (type_var_ident_opt);
+ if ((parse.lex.type == lex_lc_ident || parse.lex.type == lex_uc_ident)&& !(parse.lex.flags & 3)) {
+ T->text = parse.lex.ptr;
+ T->len = parse.lex.len;
+ T->flags = parse.lex.flags;
+ parse_lex ();
+ PARSE_OK;
+ } else if (LEX_CHAR ('_')) {
+ T->text = parse.lex.ptr;
+ T->len = parse.lex.len;
+ T->flags = parse.lex.flags;
+ parse_lex ();
+ PARSE_OK;
+ } else {
+ parse_error ("Can not parse var ident opt");
+ PARSE_FAIL;
+ }
+}
+
+struct tree *parse_nat_const (void) {
+ PARSE_INIT (type_nat_const);
+ if (parse.lex.type == lex_num) {
+ T->text = parse.lex.ptr;
+ T->len = parse.lex.len;
+ T->flags = parse.lex.flags;
+ parse_lex ();
+ PARSE_OK;
+ } else {
+ parse_error ("Can not parse nat const");
+ PARSE_FAIL;
+ }
+}
+
+struct tree *parse_type_ident (void) {
+ PARSE_INIT (type_type_ident);
+ if (parse.lex.type == lex_uc_ident && !(parse.lex.flags & 2)) {
+ T->text = parse.lex.ptr;
+ T->len = parse.lex.len;
+ T->flags = parse.lex.flags;
+ parse_lex ();
+ PARSE_OK;
+ } else if (parse.lex.type == lex_lc_ident && !(parse.lex.flags & 2)) {
+ T->text = parse.lex.ptr;
+ T->len = parse.lex.len;
+ T->flags = parse.lex.flags;
+ parse_lex ();
+ PARSE_OK;
+ } else if (LEX_CHAR ('#')) {
+ T->text = parse.lex.ptr;
+ T->len = parse.lex.len;
+ T->flags = parse.lex.flags;
+ parse_lex ();
+ PARSE_OK;
+ } else {
+ parse_error ("Can not parse type ident");
+ PARSE_FAIL;
+ }
+}
+
+struct tree *parse_term (void) {
+ PARSE_INIT (type_term);
+ while (LEX_CHAR ('%')) {
+ EXPECT ("%")
+ PARSE_ADD (type_percent);
+ }
+ if (LEX_CHAR ('(')) {
+ EXPECT ("(");
+ PARSE_TRY_PES (parse_expr);
+ EXPECT (")");
+ PARSE_OK;
+ }
+ PARSE_TRY (parse_type_ident);
+ if (S) {
+ tree_add_child (T, S);
+ if (LEX_CHAR ('<')) {
+ EXPECT ("<");
+ while (1) {
+ PARSE_TRY_PES (parse_expr);
+ if (LEX_CHAR ('>')) { break; }
+ EXPECT (",");
+ }
+ EXPECT (">");
+ }
+ PARSE_OK;
+ }
+ PARSE_TRY_OPT (parse_type_ident);
+ PARSE_TRY_OPT (parse_var_ident);
+ PARSE_TRY_OPT (parse_nat_const);
+ PARSE_FAIL;
+}
+
+struct tree *parse_nat_term (void) {
+ PARSE_INIT (type_nat_term);
+ PARSE_TRY_PES (parse_term);
+ PARSE_OK;
+}
+
+struct tree *parse_subexpr (void) {
+ PARSE_INIT (type_subexpr);
+ int was_term = 0;
+ int cc = 0;
+
+ while (1) {
+ PARSE_TRY (parse_nat_const);
+ if (S) {
+ tree_add_child (T, S);
+ } else if (!was_term) {
+ was_term = 1;
+ PARSE_TRY (parse_term);
+ if (S) {
+ tree_add_child (T, S);
+ } else {
+ break;
+ }
+ }
+ cc ++;
+ if (!LEX_CHAR ('+')) {
+ break;
+ }
+ EXPECT ("+");
+ }
+ if (!cc) {
+ PARSE_FAIL;
+ } else {
+ PARSE_OK;
+ }
+}
+
+struct tree *parse_expr (void) {
+ PARSE_INIT (type_expr);
+ int cc = 0;
+ while (1) {
+ PARSE_TRY (parse_subexpr);
+ if (S) {
+ tree_add_child (T, S);
+ cc ++;
+ } else {
+ if (cc < 1) { PARSE_FAIL; }
+ else { PARSE_OK; }
+ }
+ }
+}
+
+
+
+struct tree *parse_final_empty (void) {
+ PARSE_INIT (type_final_empty);
+ EXPECT ("Empty");
+ PARSE_TRY_PES (parse_boxed_type_ident);
+ PARSE_OK;
+}
+
+struct tree *parse_final_new (void) {
+ PARSE_INIT (type_final_new);
+ EXPECT ("New");
+ PARSE_TRY_PES (parse_boxed_type_ident);
+ PARSE_OK;
+}
+
+struct tree *parse_final_final (void) {
+ PARSE_INIT (type_final_final);
+ EXPECT ("Final");
+ PARSE_TRY_PES (parse_boxed_type_ident);
+ PARSE_OK;
+}
+
+struct tree *parse_partial_comb_app_decl (void) {
+ PARSE_INIT (type_partial_comb_app_decl);
+ PARSE_TRY_PES (parse_combinator_id);
+ while (1) {
+ PARSE_TRY_PES (parse_subexpr);
+ if (LEX_CHAR (';')) { break; }
+ }
+ PARSE_OK;
+}
+
+struct tree *parse_partial_type_app_decl (void) {
+ PARSE_INIT (type_partial_type_app_decl);
+ PARSE_TRY_PES (parse_boxed_type_ident);
+ if (LEX_CHAR ('<')) {
+ EXPECT ("<");
+ while (1) {
+ PARSE_TRY_PES (parse_expr);
+ if (LEX_CHAR ('>')) { break; }
+ EXPECT (",");
+ }
+ EXPECT (">");
+ PARSE_OK;
+ } else {
+ while (1) {
+ PARSE_TRY_PES (parse_subexpr);
+ if (LEX_CHAR (';')) { break; }
+ }
+ PARSE_OK;
+ }
+}
+
+
+
+
+struct tree *parse_multiplicity (void) {
+ PARSE_INIT (type_multiplicity);
+ PARSE_TRY_PES (parse_nat_term);
+ PARSE_OK;
+}
+
+
+struct tree *parse_type_term (void) {
+ PARSE_INIT (type_type_term);
+ PARSE_TRY_PES (parse_term);
+ PARSE_OK;
+}
+
+struct tree *parse_optional_arg_def (void) {
+ PARSE_INIT (type_optional_arg_def);
+ PARSE_TRY_PES (parse_var_ident);
+ EXPECT (".");
+ PARSE_TRY_PES (parse_nat_const);
+ EXPECT ("?");
+ PARSE_OK;
+}
+
+struct tree *parse_args4 (void) {
+ PARSE_INIT (type_args4);
+ struct parse so = save_parse ();
+ PARSE_TRY (parse_optional_arg_def);
+ if (S) {
+ tree_add_child (T, S);
+ } else {
+ load_parse (so);
+ }
+ if (LEX_CHAR ('!')) {
+ PARSE_ADD (type_exclam);
+ EXPECT ("!");
+ }
+ PARSE_TRY_PES (parse_type_term);
+ PARSE_OK;
+}
+
+struct tree *parse_args3 (void) {
+ PARSE_INIT (type_args3);
+ PARSE_TRY_PES (parse_var_ident_opt);
+ EXPECT (":");
+ struct parse so = save_parse ();
+ PARSE_TRY (parse_optional_arg_def);
+ if (S) {
+ tree_add_child (T, S);
+ } else {
+ load_parse (so);
+ }
+ if (LEX_CHAR ('!')) {
+ PARSE_ADD (type_exclam);
+ EXPECT ("!");
+ }
+ PARSE_TRY_PES (parse_type_term);
+ PARSE_OK;
+}
+
+struct tree *parse_args2 (void) {
+ PARSE_INIT (type_args2);
+ PARSE_TRY (parse_var_ident_opt);
+ if (S && LEX_CHAR (':')) {
+ tree_add_child (T, S);
+ EXPECT (":");
+ } else {
+ load_parse (save);
+ }
+ struct parse so = save_parse ();
+ PARSE_TRY (parse_optional_arg_def);
+ if (S) {
+ tree_add_child (T, S);
+ } else {
+ load_parse (so);
+ }
+ struct parse save2 = save_parse ();
+ PARSE_TRY (parse_multiplicity);
+ if (S && LEX_CHAR ('*')) {
+ tree_add_child (T, S);
+ EXPECT ("*");
+ } else {
+ load_parse (save2);
+ }
+ EXPECT ("[");
+ while (1) {
+ if (LEX_CHAR (']')) { break; }
+ PARSE_TRY_PES (parse_args);
+ }
+ EXPECT ("]");
+ PARSE_OK;
+}
+
+struct tree *parse_args1 (void) {
+ PARSE_INIT (type_args1);
+ EXPECT ("(");
+ while (1) {
+ PARSE_TRY_PES (parse_var_ident_opt);
+ if (LEX_CHAR(':')) { break; }
+ }
+ EXPECT (":");
+ struct parse so = save_parse ();
+ PARSE_TRY (parse_optional_arg_def);
+ if (S) {
+ tree_add_child (T, S);
+ } else {
+ load_parse (so);
+ }
+ if (LEX_CHAR ('!')) {
+ PARSE_ADD (type_exclam);
+ EXPECT ("!");
+ }
+ PARSE_TRY_PES (parse_type_term);
+ EXPECT (")");
+ PARSE_OK;
+}
+
+struct tree *parse_args (void) {
+ PARSE_INIT (type_args);
+ PARSE_TRY_OPT (parse_args1);
+ PARSE_TRY_OPT (parse_args2);
+ PARSE_TRY_OPT (parse_args3);
+ PARSE_TRY_OPT (parse_args4);
+ PARSE_FAIL;
+}
+
+struct tree *parse_opt_args (void) {
+ PARSE_INIT (type_opt_args);
+ while (1) {
+ PARSE_TRY_PES (parse_var_ident);
+ if (parse.lex.type == lex_char && *parse.lex.ptr == ':') { break;}
+ }
+ EXPECT (":");
+ PARSE_TRY_PES (parse_type_term);
+ PARSE_OK;
+}
+
+struct tree *parse_final_decl (void) {
+ PARSE_INIT (type_final_decl);
+ PARSE_TRY_OPT (parse_final_new);
+ PARSE_TRY_OPT (parse_final_final);
+ PARSE_TRY_OPT (parse_final_empty);
+ PARSE_FAIL;
+}
+
+struct tree *parse_partial_app_decl (void) {
+ PARSE_INIT (type_partial_app_decl);
+ PARSE_TRY_OPT (parse_partial_type_app_decl);
+ PARSE_TRY_OPT (parse_partial_comb_app_decl);
+ PARSE_FAIL;
+}
+
+struct tree *parse_result_type (void) {
+ PARSE_INIT (type_result_type);
+ PARSE_TRY_PES (parse_boxed_type_ident);
+ if (LEX_CHAR ('<')) {
+ EXPECT ("<");
+ while (1) {
+ PARSE_TRY_PES (parse_expr);
+ if (LEX_CHAR ('>')) { break; }
+ EXPECT (",");
+ }
+ EXPECT (">");
+ PARSE_OK;
+ } else {
+ while (1) {
+ if (LEX_CHAR (';')) { PARSE_OK; }
+ PARSE_TRY_PES (parse_subexpr);
+ }
+ }
+}
+
+struct tree *parse_combinator_decl (void) {
+ PARSE_INIT (type_combinator_decl);
+ PARSE_TRY_PES (parse_full_combinator_id)
+ while (1) {
+ if (LEX_CHAR ('{')) {
+ parse_lex ();
+ PARSE_TRY_PES (parse_opt_args);
+ EXPECT ("}");
+ } else {
+ break;
+ }
+ }
+ while (1) {
+ if (LEX_CHAR ('=')) { break; }
+ PARSE_TRY_PES (parse_args);
+ }
+ EXPECT ("=");
+ PARSE_ADD (type_equals);
+
+ PARSE_TRY_PES (parse_result_type);
+ PARSE_OK;
+}
+
+struct tree *parse_builtin_combinator_decl (void) {
+ PARSE_INIT (type_builtin_combinator_decl);
+ PARSE_TRY_PES (parse_full_combinator_id)
+ EXPECT ("?");
+ EXPECT ("=");
+ PARSE_TRY_PES (parse_boxed_type_ident);
+ PARSE_OK;
+}
+
+struct tree *parse_declaration (void) {
+ PARSE_INIT (type_declaration);
+ PARSE_TRY_OPT (parse_combinator_decl);
+ PARSE_TRY_OPT (parse_partial_app_decl);
+ PARSE_TRY_OPT (parse_final_decl);
+ PARSE_TRY_OPT (parse_builtin_combinator_decl);
+ PARSE_FAIL;
+}
+
+struct tree *parse_constr_declarations (void) {
+ PARSE_INIT (type_constr_declarations);
+ if (parse.lex.type == lex_triple_minus || parse.lex.type == lex_eof) { PARSE_OK; }
+ while (1) {
+ PARSE_TRY_PES (parse_declaration);
+ EXPECT (";");
+ if (parse.lex.type == lex_eof || parse.lex.type == lex_triple_minus) { PARSE_OK; }
+ }
+}
+
+struct tree *parse_fun_declarations (void) {
+ PARSE_INIT (type_fun_declarations);
+ if (parse.lex.type == lex_triple_minus || parse.lex.type == lex_eof) { PARSE_OK; }
+ while (1) {
+ PARSE_TRY_PES (parse_declaration);
+ EXPECT (";");
+ if (parse.lex.type == lex_eof || parse.lex.type == lex_triple_minus) { PARSE_OK; }
+ }
+}
+
+struct tree *parse_program (void) {
+ PARSE_INIT (type_tl_program);
+ while (1) {
+ PARSE_TRY_PES (parse_constr_declarations);
+ if (parse.lex.type == lex_eof) { PARSE_OK; }
+ if (parse.lex.type == lex_error || expect ("---") < 0 || expect ("functions") < 0 || expect ("---") < 0) { PARSE_FAIL; }
+
+ PARSE_TRY_PES (parse_fun_declarations);
+ if (parse.lex.type == lex_eof) { PARSE_OK; }
+ if (parse.lex.type == lex_error || expect ("---") < 0 || expect ("types") < 0 || expect ("---") < 0) { PARSE_FAIL; }
+ }
+}
+
+struct tree *tl_parse_lex (struct parse *_parse) {
+ assert (_parse);
+ load_parse (*_parse);
+ if (parse.lex.type == lex_none) {
+ parse_lex ();
+ }
+ if (parse.lex.type == lex_error) {
+ return 0;
+ }
+ return parse_program ();
+}
+
+int mystrcmp2 (const char *b, int len, const char *a) {
+ int c = strncmp (b, a, len);
+ return c ? a[len] ? -1 : 0 : c;
+}
+
+char *mystrdup (const char *a, int len) {
+ char *z = talloc (len + 1);
+ memcpy (z, a, len);
+ z[len] = 0;
+ return z;
+}
+
+struct tl_program *tl_program_cur;
+#define TL_TRY_PES(x) if (!(x)) { return 0; }
+
+#define tl_type_cmp(a,b) (strcmp (a->id, b->id))
+DEFINE_TREE (tl_type,struct tl_type *,tl_type_cmp,0)
+struct tree_tl_type *tl_type_tree;
+
+DEFINE_TREE (tl_constructor,struct tl_constructor *,tl_type_cmp,0)
+struct tree_tl_constructor *tl_constructor_tree;
+struct tree_tl_constructor *tl_function_tree;
+
+DEFINE_TREE (tl_var,struct tl_var *,tl_type_cmp,0)
+
+struct tl_var_value {
+ struct tl_combinator_tree *ptr;
+ struct tl_combinator_tree *val;
+ int num_val;
+};
+
+#define tl_var_value_cmp(a,b) (((char *)a.ptr) - ((char *)b.ptr))
+struct tl_var_value empty;
+DEFINE_TREE (var_value, struct tl_var_value, tl_var_value_cmp, empty)
+//tree_tl_var_t *tl_var_tree;
+
+DEFINE_TREE (tl_field,char *,strcmp, 0)
+//tree_tl_field_t *tl_field_tree;
+#define TL_FAIL return 0;
+#define TL_INIT(x) struct tl_combinator_tree *x = 0;
+#define TL_TRY(f,x) { struct tl_combinator_tree *_t = f; if (!_t) { TL_FAIL;} x = tl_union (x, _t); if (!x) { TL_FAIL; }}
+#define TL_ERROR(...) fprintf (stderr, __VA_ARGS__);
+#define TL_WARNING(...) fprintf (stderr, __VA_ARGS__);
+
+void tl_set_var_value (struct tree_var_value **T, struct tl_combinator_tree *var, struct tl_combinator_tree *value) {
+ struct tl_var_value t = {.ptr = var, .val = value, .num_val = 0};
+ if (tree_lookup_var_value (*T, t).ptr) {
+ *T = tree_delete_var_value (*T, t);
+ }
+ *T = tree_insert_var_value (*T, t, lrand48 ());
+}
+
+void tl_set_var_value_num (struct tree_var_value **T, struct tl_combinator_tree *var, struct tl_combinator_tree *value, long long num_value) {
+ struct tl_var_value t = {.ptr = var, .val = value, .num_val = num_value};
+ if (tree_lookup_var_value (*T, t).ptr) {
+ *T = tree_delete_var_value (*T, t);
+ }
+ *T = tree_insert_var_value (*T, t, lrand48 ());
+}
+
+struct tl_combinator_tree *tl_get_var_value (struct tree_var_value **T, struct tl_combinator_tree *var) {
+ struct tl_var_value t = {.ptr = var, .val = 0, .num_val = 0};
+ struct tl_var_value r = tree_lookup_var_value (*T, t);
+ return r.ptr ? r.val : 0;
+}
+
+int tl_get_var_value_num (struct tree_var_value **T, struct tl_combinator_tree *var) {
+ struct tl_var_value t = {.ptr = var, .val = 0};
+ struct tl_var_value r = tree_lookup_var_value (*T, t);
+ return r.ptr ? r.num_val : 0;
+}
+
+int namespace_level;
+
+struct tree_tl_var *vars[10];
+struct tree_tl_field *fields[10];
+struct tl_var *last_num_var[10];
+
+int tl_is_type_name (const char *id, int len) {
+ if (len == 1 && *id == '#') { return 1;}
+ int ok = id[0] >= 'A' && id[0] <= 'Z';
+ int i;
+ for (i = 0; i < len - 1; i++) if (id[i] == '.') {
+ ok = id[i + 1] >= 'A' && id[i + 1] <= 'Z';
+ }
+ return ok;
+}
+
+int tl_add_field (char *id) {
+ assert (namespace_level < 10);
+ assert (namespace_level >= 0);
+ if (tree_lookup_tl_field (fields[namespace_level], id)) {
+ return 0;
+ }
+ fields[namespace_level] = tree_insert_tl_field (fields[namespace_level], id, lrand48 ());
+ return 1;
+}
+
+void tl_clear_fields (void) {
+// tree_act_tl_field (fields[namespace_level], (void *)free);
+ fields[namespace_level] = tree_clear_tl_field (fields[namespace_level]);
+}
+
+struct tl_var *tl_add_var (char *id, struct tl_combinator_tree *ptr, int type) {
+ struct tl_var *v = talloc (sizeof (*v));
+ v->id = tstrdup (id);
+ v->type = type;
+ v->ptr = ptr;
+ v->flags = 0;
+ if (tree_lookup_tl_var (vars[namespace_level], v)) {
+ return 0;
+ }
+ vars[namespace_level] = tree_insert_tl_var (vars[namespace_level], v, lrand48 ());
+ if (type) {
+ last_num_var[namespace_level] = v;
+ }
+ return v;
+}
+
+void tl_del_var (struct tl_var *v) {
+// free (v->id);
+ tfree (v, sizeof (*v));
+}
+
+void tl_clear_vars (void) {
+ tree_act_tl_var (vars[namespace_level], tl_del_var);
+ vars[namespace_level] = tree_clear_tl_var (vars[namespace_level]);
+ last_num_var[namespace_level] = 0;
+}
+
+struct tl_var *tl_get_last_num_var (void) {
+ return last_num_var[namespace_level];
+}
+
+struct tl_var *tl_get_var (char *_id, int len) {
+ char *id = mystrdup (_id, len);
+ struct tl_var v = {.id = id};
+ int i;
+ for (i = namespace_level; i >= 0; i--) {
+ struct tl_var *w = tree_lookup_tl_var (vars[i], &v);
+ if (w) {
+ tfree (id, len + 1);
+ return w;
+ }
+ }
+ tfree (id, len + 1);
+ return 0;
+}
+
+void namespace_push (void) {
+ namespace_level ++;
+ assert (namespace_level < 10);
+ tl_clear_vars ();
+ tl_clear_fields ();
+}
+
+void namespace_pop (void) {
+ namespace_level --;
+ assert (namespace_level >= 0);
+}
+
+struct tl_type *tl_get_type (const char *_id, int len) {
+ char *id = mystrdup (_id, len);
+ struct tl_type _t = {.id = id};
+ struct tl_type *r = tree_lookup_tl_type (tl_type_tree, &_t);
+ tfree (id, len + 1);
+ return r;
+}
+
+struct tl_type *tl_add_type (const char *_id, int len, int params_num, long long params_types) {
+ char *id = talloc (len + 1);
+ memcpy (id, _id, len);
+ id[len] = 0;
+ struct tl_type _t = {.id = id};
+ struct tl_type *_r = 0;
+ if ((_r = tree_lookup_tl_type (tl_type_tree, &_t))) {
+ tfree (id, len + 1);
+ if (params_num >= 0 && (_r->params_num != params_num || _r->params_types != params_types)) {
+ TL_ERROR ("Wrong params_num or types for type %s\n", _r->id);
+ return 0;
+ }
+ return _r;
+ }
+ struct tl_type *t = talloc (sizeof (*t));
+ t->id = id;
+ t->print_id = tstrdup (t->id);
+ int i;
+ for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') {
+ t->print_id[i] = '$';
+ }
+ t->name = 0;
+ t->constructors_num = 0;
+ t->constructors = 0;
+ t->flags = 0;
+ t->real_id = 0;
+ if (params_num >= 0) {
+ assert (params_num <= 64);
+ t->params_num = params_num;
+ t->params_types = params_types;
+ } else {
+ t->flags |= 4;
+ t->params_num = -1;
+ }
+ tl_type_tree = tree_insert_tl_type (tl_type_tree, t, lrand48 ());
+ total_types_num ++;
+ return t;
+}
+
+void tl_add_type_param (struct tl_type *t, int x) {
+ assert (t->flags & 4);
+ assert (t->params_num <= 64);
+ if (x) {
+ t->params_types |= (1ull << (t->params_num ++));
+ } else {
+ t->params_num ++;
+ }
+}
+
+int tl_type_set_params (struct tl_type *t, int x, long long y) {
+ if (t->flags & 4) {
+ t->params_num = x;
+ t->params_types = y;
+ t->flags &= ~4;
+ } else {
+ if (t->params_num != x || t->params_types != y) {
+ fprintf (stderr, "Wrong num of params (type %s)\n", t->id);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+void tl_type_finalize (struct tl_type *t) {
+ t->flags &= ~4;
+}
+
+struct tl_constructor *tl_get_constructor (const char *_id, int len) {
+ char *id = mystrdup (_id, len);
+ struct tl_constructor _t = {.id = id};
+ struct tl_constructor *r = tree_lookup_tl_constructor (tl_constructor_tree, &_t);
+ tfree (id, len + 1);
+ return r;
+}
+
+struct tl_constructor *tl_add_constructor (struct tl_type *a, const char *_id, int len, int force_magic) {
+ assert (a);
+ if (a->flags & 1) {
+ TL_ERROR ("New constructor for type `%s` after final statement\n", a->id);
+ return 0;
+ }
+ int x = 0;
+ while (x < len && (_id[x] != '#' || force_magic)) { x++; }
+ char *id = talloc (x + 1);
+ memcpy (id, _id, x);
+ id[x] = 0;
+
+ unsigned magic = 0;
+ if (x < len) {
+ assert (len - x >= 6 && len - x <= 9);
+ int i;
+ for (i = 1; i < len - x; i++) {
+ magic = (magic << 4) + (_id[x + i] <= '9' ? _id[x + i] - '0' : _id[x + i] - 'a' + 10);
+ }
+ assert (magic && magic != (unsigned)-1);
+ }
+
+ len = x;
+ if (*id != '_') {
+ struct tl_constructor _t = {.id = id};
+ if (tree_lookup_tl_constructor (tl_constructor_tree, &_t)) {
+ TL_ERROR ("Duplicate constructor id `%s`\n", id);
+ tfree (id, len + 1);
+ return 0;
+ }
+ } else {
+ assert (len == 1);
+ }
+
+ struct tl_constructor *t = talloc (sizeof (*t));
+ t->type = a;
+ t->name = magic;
+ t->id = id;
+ t->print_id = tstrdup (id);
+ t->real_id = 0;
+
+ int i;
+ for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') {
+ t->print_id[i] = '$';
+ }
+
+ t->left = t->right = 0;
+ a->constructors = realloc (a->constructors, sizeof (void *) * (a->constructors_num + 1));
+ assert (a->constructors);
+ a->constructors[a->constructors_num ++] = t;
+ if (*id != '_') {
+ tl_constructor_tree = tree_insert_tl_constructor (tl_constructor_tree, t, lrand48 ());
+ } else {
+ a->flags |= FLAG_DEFAULT_CONSTRUCTOR;
+ }
+ total_constructors_num ++;
+ return t;
+}
+
+struct tl_constructor *tl_get_function (const char *_id, int len) {
+ char *id = mystrdup (_id, len);
+ struct tl_constructor _t = {.id = id};
+ struct tl_constructor *r = tree_lookup_tl_constructor (tl_function_tree, &_t);
+ tfree (id, len + 1);
+ return r;
+}
+
+struct tl_constructor *tl_add_function (struct tl_type *a, const char *_id, int len, int force_magic) {
+// assert (a);
+ int x = 0;
+ while (x < len && ((_id[x] != '#') || force_magic)) { x++; }
+ char *id = talloc (x + 1);
+ memcpy (id, _id, x);
+ id[x] = 0;
+
+ unsigned magic = 0;
+ if (x < len) {
+ assert (len - x >= 6 && len - x <= 9);
+ int i;
+ for (i = 1; i < len - x; i++) {
+ magic = (magic << 4) + (_id[x + i] <= '9' ? _id[x + i] - '0' : _id[x + i] - 'a' + 10);
+ }
+ assert (magic && magic != (unsigned)-1);
+ }
+
+ len = x;
+
+ struct tl_constructor _t = {.id = id};
+ if (tree_lookup_tl_constructor (tl_function_tree, &_t)) {
+ TL_ERROR ("Duplicate function id `%s`\n", id);
+ tfree (id, len + 1);
+ return 0;
+ }
+
+ struct tl_constructor *t = talloc (sizeof (*t));
+ t->type = a;
+ t->name = magic;
+ t->id = id;
+ t->print_id = tstrdup (id);
+ t->real_id = 0;
+
+ int i;
+ for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') {
+ t->print_id[i] = '$';
+ }
+
+ t->left = t->right = 0;
+ tl_function_tree = tree_insert_tl_constructor (tl_function_tree, t, lrand48 ());
+ total_functions_num ++;
+ return t;
+}
+
+static char buf[(1 << 20)];
+int buf_pos;
+
+struct tl_combinator_tree *alloc_ctree_node (void) {
+ struct tl_combinator_tree *T = talloc (sizeof (*T));
+ assert (T);
+ memset (T, 0, sizeof (*T));
+ return T;
+}
+
+struct tl_combinator_tree *tl_tree_dup (struct tl_combinator_tree *T) {
+ if (!T) { return 0; }
+ struct tl_combinator_tree *S = talloc (sizeof (*S));
+ memcpy (S, T, sizeof (*S));
+ S->left = tl_tree_dup (T->left);
+ S->right = tl_tree_dup (T->right);
+ return S;
+}
+
+struct tl_type *tl_tree_get_type (struct tl_combinator_tree *T) {
+ assert (T->type == type_type);
+ if (T->act == act_array) { return 0;}
+ while (T->left) {
+ T = T->left;
+ if (T->act == act_array) { return 0;}
+ assert (T->type == type_type);
+ }
+ assert (T->act == act_type || T->act == act_var || T->act == act_array);
+ return T->act == act_type ? T->data : 0;
+}
+
+void tl_tree_set_len (struct tl_combinator_tree *T) {
+ TL_INIT (H);
+ H = T;
+ while (H->left) {
+ H->left->type_len = H->type_len + 1;
+ H = H->left;
+ }
+ assert (H->type == type_type);
+ struct tl_type *t = H->data;
+ assert (t);
+ assert (H->type_len == t->params_num);
+}
+
+void tl_buf_reset (void) {
+ buf_pos = 0;
+}
+
+void tl_buf_add_string (char *s, int len) {
+ if (len < 0) { len = strlen (s); }
+ buf[buf_pos ++] = ' ';
+ memcpy (buf + buf_pos, s, len); buf_pos += len;
+ buf[buf_pos] = 0;
+}
+
+void tl_buf_add_string_nospace (char *s, int len) {
+ if (len < 0) { len = strlen (s); }
+// if (buf_pos) { buf[buf_pos ++] = ' '; }
+ memcpy (buf + buf_pos, s, len); buf_pos += len;
+ buf[buf_pos] = 0;
+}
+
+void tl_buf_add_string_q (char *s, int len, int x) {
+ if (x) {
+ tl_buf_add_string (s, len);
+ } else {
+ tl_buf_add_string_nospace (s, len);
+ }
+}
+
+
+void tl_buf_add_tree (struct tl_combinator_tree *T, int x) {
+ if (!T) { return; }
+ assert (T != (void *)-1l && T != (void *)-2l);
+ switch (T->act) {
+ case act_question_mark:
+ tl_buf_add_string_q ("?", -1, x);
+ return;
+ case act_type:
+ if ((T->flags & 1) && !(T->flags & 4)) {
+ tl_buf_add_string_q ("%", -1, x);
+ x = 0;
+ }
+ if (T->flags & 2) {
+ tl_buf_add_string_q ((char *)T->data, -1, x);
+ } else {
+ struct tl_type *t = T->data;
+ if (T->flags & 4) {
+ assert (t->constructors_num == 1);
+ tl_buf_add_string_q (t->constructors[0]->real_id ? t->constructors[0]->real_id : t->constructors[0]->id, -1, x);
+ } else {
+ tl_buf_add_string_q (t->real_id ? t->real_id : t->id, -1, x);
+ }
+ }
+ return;
+ case act_field:
+ if (T->data) {
+ tl_buf_add_string_q ((char *)T->data, -1, x);
+ x = 0;
+ tl_buf_add_string_q (":", -1, 0);
+ }
+ tl_buf_add_tree (T->left, x);
+ tl_buf_add_tree (T->right, 1);
+ return;
+ case act_union:
+ tl_buf_add_tree (T->left, x);
+ tl_buf_add_tree (T->right, 1);
+ return;
+ case act_var:
+ {
+ if (T->data == (void *)-1l) { return; }
+ struct tl_combinator_tree *v = T->data;
+ tl_buf_add_string_q ((char *)v->data, -1, x);
+ if (T->type == type_num && T->type_flags) {
+ static char _buf[30];
+ sprintf (_buf, "+%lld", T->type_flags);
+ tl_buf_add_string_q (_buf, -1, 0);
+ }
+ }
+ return;
+ case act_arg:
+ tl_buf_add_tree (T->left, x);
+ tl_buf_add_tree (T->right, 1);
+ return;
+ case act_array:
+ if (T->left && !(T->left->flags & 128)) {
+ tl_buf_add_tree (T->left, x);
+ x = 0;
+ tl_buf_add_string_q ("*", -1, x);
+ }
+ tl_buf_add_string_q ("[", -1, x);
+ tl_buf_add_tree (T->right, 1);
+ tl_buf_add_string_q ("]", -1, 1);
+ return;
+ case act_plus:
+ tl_buf_add_tree (T->left, x);
+ tl_buf_add_string_q ("+", -1, 0);
+ tl_buf_add_tree (T->right, 0);
+ return;
+ case act_nat_const:
+ {
+ static char _buf[30];
+ snprintf (_buf, 29, "%lld", T->type_flags);
+ tl_buf_add_string_q (_buf, -1, x);
+ return;
+ }
+ case act_opt_field:
+ {
+ struct tl_combinator_tree *v = T->left->data;
+ tl_buf_add_string_q ((char *)v->data, -1, x);
+ tl_buf_add_string_q (".", -1, 0);
+ static char _buf[30];
+ sprintf (_buf, "%lld", T->left->type_flags);
+ tl_buf_add_string_q (_buf, -1, 0);
+ tl_buf_add_string_q ("?", -1, 0);
+ tl_buf_add_tree (T->right, 0);
+ return;
+ }
+
+ default:
+ fprintf (stderr, "%s %s\n", TL_ACT (T->act), TL_TYPE (T->type));
+ assert (0);
+ return;
+ }
+}
+
+int tl_count_combinator_name (struct tl_constructor *c) {
+ assert (c);
+ tl_buf_reset ();
+ tl_buf_add_string_nospace (c->real_id ? c->real_id : c->id, -1);
+ tl_buf_add_tree (c->left, 1);
+ tl_buf_add_string ("=", -1);
+ tl_buf_add_tree (c->right, 1);
+ //fprintf (stderr, "%.*s\n", buf_pos, buf);
+ if (!c->name) {
+ c->name = crc32 (CRC32_INITIAL, (void *) buf, buf_pos);
+ }
+ return c->name;
+}
+
+int tl_print_combinator (struct tl_constructor *c) {
+ tl_buf_reset ();
+ tl_buf_add_string_nospace (c->real_id ? c->real_id : c->id, -1);
+ static char _buf[10];
+ sprintf (_buf, "#%08x", c->name);
+ tl_buf_add_string_nospace (_buf, -1);
+ tl_buf_add_tree (c->left, 1);
+ tl_buf_add_string ("=", -1);
+ tl_buf_add_tree (c->right, 1);
+ if (output_expressions >= 1) {
+ fprintf (stderr, "%.*s\n", buf_pos, buf);
+ }
+/* if (!c->name) {
+ c->name = crc32 (CRC32_INITIAL, (void *) bbuf, buf_pos);
+ }*/
+ return c->name;
+}
+
+int _tl_finish_subtree (struct tl_combinator_tree *R, int x, long long y) {
+ assert (R->type == type_type);
+ assert (R->type_len < 0);
+ assert (R->act == act_arg || R->act == act_type);
+ R->type_len = x;
+ R->type_flags = y;
+ if (R->act == act_type) {
+ struct tl_type *t = R->data;
+ assert (t);
+ return tl_type_set_params (t, x, y);
+ }
+ assert ((R->right->type == type_type && R->right->type_len == 0) || R->right->type == type_num || R->right->type == type_num_value);
+ return _tl_finish_subtree (R->left, x + 1, y * 2 + (R->right->type == type_num || R->right->type == type_num_value));
+}
+
+int tl_finish_subtree (struct tl_combinator_tree *R) {
+ assert (R);
+ if (R->type != type_type) {
+ return 1;
+ }
+ if (R->type_len >= 0) {
+ if (R->type_len > 0) {
+ TL_ERROR ("Not enough params\n");
+ return 0;
+ }
+ return 1;
+ }
+ return _tl_finish_subtree (R, 0, 0);
+}
+
+struct tl_combinator_tree *tl_union (struct tl_combinator_tree *L, struct tl_combinator_tree *R) {
+ if (!L) { return R; }
+ if (!R) { return L; }
+ TL_INIT (v);
+ v = alloc_ctree_node ();
+ v->left = L;
+ v->right = R;
+ switch (L->type) {
+ case type_num:
+ if (R->type != type_num_value) {
+ TL_ERROR ("Union: type mistmatch\n");
+ return 0;
+ }
+ tfree (v, sizeof (*v));
+ L->type_flags += R->type_flags;
+ return L;
+ case type_num_value:
+ if (R->type != type_num_value && R->type != type_num) {
+ TL_ERROR ("Union: type mistmatch\n");
+ return 0;
+ }
+ tfree (v, sizeof (*v));
+ R->type_flags += L->type_flags;
+ return R;
+ case type_list_item:
+ case type_list:
+ if (R->type != type_list_item) {
+ TL_ERROR ("Union: type mistmatch\n");
+ return 0;
+ }
+ v->type = type_list;
+ v->act = act_union;
+ return v;
+ case type_type:
+ if (L->type_len == 0) {
+ TL_ERROR ("Arguments number exceeds type arity\n");
+ return 0;
+ }
+ if (R->type != type_num && R->type != type_type && R->type != type_num_value) {
+ TL_ERROR ("Union: type mistmatch\n");
+ return 0;
+ }
+ if (R->type_len < 0) {
+ if (!tl_finish_subtree (R)) {
+ return 0;
+ }
+ }
+ if (R->type_len > 0) {
+ TL_ERROR ("Argument type must have full number of arguments\n");
+ return 0;
+ }
+ if (L->type_len > 0 && ((L->type_flags & 1) != (R->type == type_num || R->type == type_num_value))) {
+ TL_ERROR ("Argument types mistmatch: L->type_flags = %lld, R->type = %s\n", L->flags, TL_TYPE (R->type));
+ return 0;
+ }
+ v->type = type_type;
+ v->act = act_arg;
+ v->type_len = L->type_len > 0 ? L->type_len - 1 : -1;
+ v->type_flags = L->type_flags >> 1;
+ return v;
+ default:
+ assert (0);
+ return 0;
+ }
+}
+
+struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s);
+struct tl_combinator_tree *tl_parse_term (struct tree *T, int s) {
+ assert (T->type == type_term);
+ int i = 0;
+ while (i < T->nc && T->c[i]->type == type_percent) { i ++; s ++; }
+ assert (i < T->nc);
+ TL_INIT (L);
+ while (i < T->nc) {
+ TL_TRY (tl_parse_any_term (T->c[i], s), L);
+ s = 0;
+ i ++;
+ }
+ return L;
+}
+
+
+struct tl_combinator_tree *tl_parse_type_term (struct tree *T, int s) {
+ assert (T->type == type_type_term);
+ assert (T->nc == 1);
+ struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s);
+ if (!Z || Z->type != type_type) { if (Z) { TL_ERROR ("type_term: found type %s\n", TL_TYPE (Z->type)); } TL_FAIL; }
+ return Z;
+}
+
+struct tl_combinator_tree *tl_parse_nat_term (struct tree *T, int s) {
+ assert (T->type == type_nat_term);
+ assert (T->nc == 1);
+ struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s);
+ if (!Z || (Z->type != type_num && Z->type != type_num_value)) { if (Z) { TL_ERROR ("nat_term: found type %s\n", TL_TYPE (Z->type)); }TL_FAIL; }
+ return Z;
+}
+
+struct tl_combinator_tree *tl_parse_subexpr (struct tree *T, int s) {
+ assert (T->type == type_subexpr);
+ assert (T->nc >= 1);
+ int i;
+ TL_INIT (L);
+ for (i = 0; i < T->nc; i++) {
+ TL_TRY (tl_parse_any_term (T->c[i], s), L);
+ s = 0;
+ }
+ return L;
+}
+
+struct tl_combinator_tree *tl_parse_expr (struct tree *T, int s) {
+ assert (T->type == type_expr);
+ assert (T->nc >= 1);
+ int i;
+ TL_INIT (L);
+ for (i = 0; i < T->nc; i++) {
+ TL_TRY (tl_parse_subexpr (T->c[i], s), L);
+ s = 0;
+ }
+ return L;
+}
+
+struct tl_combinator_tree *tl_parse_nat_const (struct tree *T, int s) {
+ assert (T->type == type_nat_const);
+ assert (!T->nc);
+ if (s > 0) {
+ TL_ERROR ("Nat const can not precede with %%\n");
+ TL_FAIL;
+ }
+ assert (T->type == type_nat_const);
+ assert (!T->nc);
+ TL_INIT (L);
+ L = alloc_ctree_node ();
+ L->act = act_nat_const;
+ L->type = type_num_value;
+ int i;
+ long long x = 0;
+ for (i = 0; i < T->len; i++) {
+ x = x * 10 + T->text[i] - '0';
+ }
+ L->type_flags = x;
+ return L;
+}
+
+struct tl_combinator_tree *tl_parse_ident (struct tree *T, int s) {
+ assert (T->type == type_type_ident || T->type == type_var_ident || T->type == type_boxed_type_ident);
+ assert (!T->nc);
+ struct tl_var *v = tl_get_var (T->text, T->len);
+ TL_INIT (L);
+ if (v) {
+ L = alloc_ctree_node ();
+ L->act = act_var;
+ L->type = v->type ? type_num : type_type;
+ if (L->type == type_num && s) {
+ TL_ERROR ("Nat var can not precede with %%\n");
+ TL_FAIL;
+ } else {
+ if (s) {
+ L->flags |= 1;
+ }
+ }
+ L->type_len = 0;
+ L->type_flags = 0;
+ L->data = v->ptr;
+ return L;
+ }
+
+/* if (!mystrcmp2 (T->text, T->len, "#") || !mystrcmp2 (T->text, T->len, "Type")) {
+ L = alloc_ctree_node ();
+ L->act = act_type;
+ L->flags |= 2;
+ L->data = tl_get_type (T->text, T->len);
+ assert (L->data);
+ L->type = type_type;
+ L->type_len = 0;
+ L->type_flags = 0;
+ return L;
+ }*/
+
+ struct tl_constructor *c = tl_get_constructor (T->text, T->len);
+ if (c) {
+ assert (c->type);
+ if (c->type->constructors_num != 1) {
+ TL_ERROR ("Constructor can be used only if it is the only constructor of the type\n");
+ return 0;
+ }
+ c->type->flags |= 1;
+ L = alloc_ctree_node ();
+ L->act = act_type;
+ L->flags |= 5;
+ L->data = c->type;
+ L->type = type_type;
+ L->type_len = c->type->params_num;
+ L->type_flags = c->type->params_types;
+ return L;
+ }
+ int x = tl_is_type_name (T->text, T->len);
+ if (x) {
+ struct tl_type *t = tl_add_type (T->text, T->len, -1, 0);
+ L = alloc_ctree_node ();
+ if (s) {
+ L->flags |= 1;
+ t->flags |= 8;
+ }
+ L->act = act_type;
+ L->data = t;
+ L->type = type_type;
+ L->type_len = t->params_num;
+ L->type_flags = t->params_types;
+ return L;
+ } else {
+ TL_ERROR ("Not a type/var ident `%.*s`\n", T->len, T->text);
+ return 0;
+ }
+}
+
+struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s) {
+ switch (T->type) {
+ case type_type_term:
+ return tl_parse_type_term (T, s);
+ case type_nat_term:
+ return tl_parse_nat_term (T, s);
+ case type_term:
+ return tl_parse_term (T, s);
+ case type_expr:
+ return tl_parse_expr (T, s);
+ case type_subexpr:
+ return tl_parse_subexpr (T, s);
+ case type_nat_const:
+ return tl_parse_nat_const (T, s);
+ case type_type_ident:
+ case type_var_ident:
+ return tl_parse_ident (T, s);
+ default:
+ fprintf (stderr, "type = %d\n", T->type);
+ assert (0);
+ return 0;
+ }
+}
+
+struct tl_combinator_tree *tl_parse_multiplicity (struct tree *T) {
+ assert (T->type == type_multiplicity);
+ assert (T->nc == 1);
+ return tl_parse_nat_term (T->c[0], 0);
+}
+
+struct tl_combinator_tree *tl_parse_opt_args (struct tree *T) {
+ assert (T);
+ assert (T->type == type_opt_args);
+ assert (T->nc >= 2);
+ TL_INIT (R);
+ TL_TRY (tl_parse_type_term (T->c[T->nc - 1], 0), R);
+ assert (R->type == type_type && !R->type_len);
+ assert (tl_finish_subtree (R));
+ struct tl_type *t = tl_tree_get_type (R);
+ //assert (t);
+ int tt = -1;
+ if (t && !strcmp (t->id, "#")) {
+ tt = 1;
+ } else if (t && !strcmp (t->id, "Type")) {
+ tt = 0;
+ }
+ if (tt < 0) {
+ TL_ERROR ("Optargs can be only of type # or Type\n");
+ TL_FAIL;
+ }
+
+ int i;
+ for (i = 0; i < T->nc - 1; i++) {
+ if (T->c[i]->type != type_var_ident) {
+ TL_ERROR ("Variable name expected\n");
+ TL_FAIL;
+ }
+ if (T->c[i]->len == 1 && *T->c[i]->text == '_') {
+ TL_ERROR ("Variables can not be unnamed\n");
+ TL_FAIL;
+ }
+ }
+ TL_INIT (H);
+// for (i = T->nc - 2; i >= (T->nc >= 2 ? 0 : -1); i--) {
+ for (i = 0; i <= T->nc - 2; i++) {
+ TL_INIT (S); S = alloc_ctree_node ();
+ S->left = (i == T->nc - 2) ? R : tl_tree_dup (R) ; S->right = 0;
+ S->type = type_list_item;
+ S->type_len = 0;
+ S->act = act_field;
+ S->data = i >= 0 ? mystrdup (T->c[i]->text, T->c[i]->len) : 0;
+ if (tt >= 0) {
+ assert (S->data);
+ tl_add_var (S->data, S, tt);
+ }
+ S->flags = 33;
+ H = tl_union (H, S);
+ }
+ return H;
+}
+
+struct tl_combinator_tree *tl_parse_args (struct tree *T);
+struct tl_combinator_tree *tl_parse_args2 (struct tree *T) {
+ assert (T);
+ assert (T->type == type_args2);
+ assert (T->nc >= 1);
+ TL_INIT (R);
+ TL_INIT (L);
+ int x = 0;
+ char *field_name = 0;
+ if (T->c[x]->type == type_var_ident_opt || T->c[x]->type == type_var_ident) {
+ field_name = mystrdup (T->c[x]->text, T->c[x]->len);
+ if (!tl_add_field (field_name)) {
+ TL_ERROR ("Duplicate field name %s\n", field_name);
+ TL_FAIL;
+ }
+ x ++;
+ }
+ //fprintf (stderr, "%d %d\n", x, T->nc);
+ if (T->c[x]->type == type_multiplicity) {
+ L = tl_parse_multiplicity (T->c[x]);
+ if (!L) { TL_FAIL;}
+ x ++;
+ } else {
+ struct tl_var *v = tl_get_last_num_var ();
+ if (!v) {
+ TL_ERROR ("Expected multiplicity or nat var\n");
+ TL_FAIL;
+ }
+ L = alloc_ctree_node ();
+ L->act = act_var;
+ L->type = type_num;
+ L->flags |= 128;
+ L->type_len = 0;
+ L->type_flags = 0;
+ L->data = v->ptr;
+ ((struct tl_combinator_tree *)(v->ptr))->flags |= 256;
+ }
+ namespace_push ();
+ while (x < T->nc) {
+ TL_TRY (tl_parse_args (T->c[x]), R);
+ x ++;
+ }
+ namespace_pop ();
+ struct tl_combinator_tree *S = alloc_ctree_node ();
+ S->type = type_type;
+ S->type_len = 0;
+ S->act = act_array;
+ S->left = L;
+ S->right = R;
+ //S->data = field_name;
+
+ struct tl_combinator_tree *H = alloc_ctree_node ();
+ H->type = type_list_item;
+ H->act = act_field;
+ H->left = S;
+ H->right = 0;
+ H->data = field_name;
+ H->type_len = 0;
+
+ return H;
+}
+
+void tl_mark_vars (struct tl_combinator_tree *T);
+struct tl_combinator_tree *tl_parse_args134 (struct tree *T) {
+ assert (T);
+ assert (T->type == type_args1 || T->type == type_args3 || T->type == type_args4);
+ assert (T->nc >= 1);
+ TL_INIT (R);
+ TL_TRY (tl_parse_type_term (T->c[T->nc - 1], 0), R);
+ assert (tl_finish_subtree (R));
+ assert (R->type == type_type && !R->type_len);
+ struct tl_type *t = tl_tree_get_type (R);
+ //assert (t);
+ int tt = -1;
+ if (t && !strcmp (t->id, "#")) {
+ tt = 1;
+ } else if (t && !strcmp (t->id, "Type")) {
+ tt = 0;
+ }
+
+/* if (tt >= 0 && T->nc == 1) {
+ TL_ERROR ("Variables can not be unnamed (type %d)\n", tt);
+ }*/
+ int last = T->nc - 2;
+ int excl = 0;
+ if (last >= 0 && T->c[last]->type == type_exclam) {
+ excl ++;
+ tl_mark_vars (R);
+ last --;
+ }
+ if (last >= 0 && T->c[last]->type == type_optional_arg_def) {
+ assert (T->c[last]->nc == 2);
+ TL_INIT (E); E = alloc_ctree_node ();
+ E->type = type_type;
+ E->act = act_opt_field;
+ E->left = tl_parse_ident (T->c[last]->c[0], 0);
+ int i;
+ long long x = 0;
+ for (i = 0; i < T->c[last]->c[1]->len; i++) {
+ x = x * 10 + T->c[last]->c[1]->text[i] - '0';
+ }
+ E->left->type_flags = x;
+ E->type_flags = R->type_flags;
+ E->type_len = R->type_len;
+ E->right = R;
+ R = E;
+ last --;
+ }
+ int i;
+ for (i = 0; i < last; i++) {
+ if (T->c[i]->type != type_var_ident && T->c[i]->type != type_var_ident_opt) {
+ TL_ERROR ("Variable name expected\n");
+ TL_FAIL;
+ }
+/* if (tt >= 0 && (T->nc == 1 || (T->c[i]->len == 1 && *T->c[i]->text == '_'))) {
+ TL_ERROR ("Variables can not be unnamed\n");
+ TL_FAIL;
+ }*/
+ }
+ TL_INIT (H);
+// for (i = T->nc - 2; i >= (T->nc >= 2 ? 0 : -1); i--) {
+ for (i = (last >= 0 ? 0 : -1); i <= last; i++) {
+ TL_INIT (S); S = alloc_ctree_node ();
+ S->left = (i == last) ? R : tl_tree_dup (R) ; S->right = 0;
+ S->type = type_list_item;
+ S->type_len = 0;
+ S->act = act_field;
+ S->data = i >= 0 ? mystrdup (T->c[i]->text, T->c[i]->len) : 0;
+ if (excl) {
+ S->flags |= FLAG_EXCL;
+ }
+ if (S->data && (T->c[i]->len >= 2 || *T->c[i]->text != '_')) {
+ if (!tl_add_field (S->data)) {
+ TL_ERROR ("Duplicate field name %s\n", (char *)S->data);
+ TL_FAIL;
+ }
+ }
+ if (tt >= 0) {
+ char *name = S->data;
+ static char s[21];
+ if (!name) {
+ sprintf (s, "%lld", lrand48 () * (1ll << 32) + lrand48 ());
+ name = s; // will be strdup'd, so reference-to-stack is fine.
+ }
+ struct tl_var *v = tl_add_var (name, S, tt);
+ if (!v) {TL_FAIL;}
+ v->flags |= 2;
+ }
+
+ H = tl_union (H, S);
+ }
+ return H;
+}
+
+
+struct tl_combinator_tree *tl_parse_args (struct tree *T) {
+ assert (T->type == type_args);
+ assert (T->nc == 1);
+ switch (T->c[0]->type) {
+ case type_args1:
+ return tl_parse_args134 (T->c[0]);
+ case type_args2:
+ return tl_parse_args2 (T->c[0]);
+ case type_args3:
+ return tl_parse_args134 (T->c[0]);
+ case type_args4:
+ return tl_parse_args134 (T->c[0]);
+ default:
+ assert (0);
+ return 0;
+ }
+}
+
+void tl_mark_vars (struct tl_combinator_tree *T) {
+ if (!T) { return; }
+ if (T->act == act_var) {
+ char *id = ((struct tl_combinator_tree *)(T->data))->data;
+ struct tl_var *v = tl_get_var (id, strlen (id));
+ assert (v);
+ v->flags |= 1;
+ }
+ tl_mark_vars (T->left);
+ tl_mark_vars (T->right);
+}
+
+struct tl_combinator_tree *tl_parse_result_type (struct tree *T) {
+ assert (T->type == type_result_type);
+ assert (T->nc >= 1);
+ assert (T->nc <= 64);
+
+ TL_INIT (L);
+
+ if (tl_get_var (T->c[0]->text, T->c[0]->len)) {
+ if (T->nc != 1) {
+ TL_ERROR ("Variable can not take params\n");
+ TL_FAIL;
+ }
+ L = alloc_ctree_node ();
+ L->act = act_var;
+ L->type = type_type;
+ struct tl_var *v = tl_get_var (T->c[0]->text, T->c[0]->len);
+ if (v->type) {
+ TL_ERROR ("Type mistmatch\n");
+ TL_FAIL;
+ }
+ L->data = v->ptr;
+// assert (v->ptr);
+ } else {
+ L = alloc_ctree_node ();
+ L->act = act_type;
+ L->type = type_type;
+ struct tl_type *t = tl_add_type (T->c[0]->text, T->c[0]->len, -1, 0);
+ assert (t);
+ L->type_len = t->params_num;
+ L->type_flags = t->params_types;
+ L->data = t;
+
+ int i;
+ for (i = 1; i < T->nc; i++) {
+ TL_TRY (tl_parse_any_term (T->c[i], 0), L);
+ assert (L->right);
+ assert (L->right->type == type_num || L->right->type == type_num_value || (L->right->type == type_type && L->right->type_len == 0));
+ }
+ }
+
+ if (!tl_finish_subtree (L)) {
+ TL_FAIL;
+ }
+
+ tl_mark_vars (L);
+ return L;
+}
+
+int __ok;
+void tl_var_check_used (struct tl_var *v) {
+ __ok = __ok && (v->flags & 3);
+}
+
+int tl_parse_combinator_decl (struct tree *T, int fun) {
+ assert (T->type == type_combinator_decl);
+ assert (T->nc >= 3);
+ namespace_level = 0;
+ tl_clear_vars ();
+ tl_clear_fields ();
+ TL_INIT (L);
+ TL_INIT (R);
+
+ int i = 1;
+ while (i < T->nc - 2 && T->c[i]->type == type_opt_args) {
+ TL_TRY (tl_parse_opt_args (T->c[i]), L);
+ i++;
+ }
+ while (i < T->nc - 2 && T->c[i]->type == type_args) {
+ TL_TRY (tl_parse_args (T->c[i]), L);
+ i++;
+ }
+ assert (i == T->nc - 2 && T->c[i]->type == type_equals);
+ i ++;
+
+ R = tl_parse_result_type (T->c[i]);
+ if (!R) { TL_FAIL; }
+
+ struct tl_type *t = tl_tree_get_type (R);
+ if (!fun && !t) {
+ TL_ERROR ("Only functions can return variables\n");
+ }
+ assert (t || fun);
+
+ assert (namespace_level == 0);
+ __ok = 1;
+ tree_act_tl_var (vars[0], tl_var_check_used);
+ if (!__ok) {
+ TL_ERROR ("Not all variables are used in right side\n");
+ TL_FAIL;
+ }
+
+ if (tl_get_constructor (T->c[0]->text, T->c[0]->len) || tl_get_function (T->c[0]->text, T->c[0]->len)) {
+ TL_ERROR ("Duplicate combinator id %.*s\n", T->c[0]->len, T->c[0]->text);
+ return 0;
+ }
+ struct tl_constructor *c = !fun ? tl_add_constructor (t, T->c[0]->text, T->c[0]->len, 0) : tl_add_function (t, T->c[0]->text, T->c[0]->len, 0);
+ if (!c) { TL_FAIL; }
+ c->left = L;
+ c->right = R;
+
+ if (!c->name) {
+ tl_count_combinator_name (c);
+ }
+ tl_print_combinator (c);
+
+ return 1;
+}
+
+void change_var_ptrs (struct tl_combinator_tree *O, struct tl_combinator_tree *D, struct tree_var_value **V) {
+ if (!O || !D) {
+ assert (!O && !D);
+ return;
+ }
+ if (O->act == act_field) {
+ struct tl_type *t = tl_tree_get_type (O->left);
+ if (t && (!strcmp (t->id, "#") || !strcmp (t->id, "Type"))) {
+ tl_set_var_value (V, O, D);
+ }
+ }
+ if (O->act == act_var) {
+ assert (D->data == O->data);
+ D->data = tl_get_var_value (V, O->data);
+ assert (D->data);
+ }
+ change_var_ptrs (O->left, D->left, V);
+ change_var_ptrs (O->right, D->right, V);
+}
+
+struct tl_combinator_tree *change_first_var (struct tl_combinator_tree *O, struct tl_combinator_tree **X, struct tl_combinator_tree *Y) {
+ if (!O) { return (void *)-2l; };
+ if (O->act == act_field && !*X) {
+ struct tl_type *t = tl_tree_get_type (O->left);
+ if (t && !strcmp (t->id, "#")) {
+ if (Y->type != type_num && Y->type != type_num_value) {
+ TL_ERROR ("change_var: Type mistmatch\n");
+ return 0;
+ } else {
+ *X = O;
+ return (void *)-1l;
+ }
+ }
+ if (t && !strcmp (t->id, "Type")) {
+ if (Y->type != type_type || Y->type_len != 0) {
+ TL_ERROR ("change_var: Type mistmatch\n");
+ return 0;
+ } else {
+ *X = O;
+ return (void *)-1l;
+ }
+ }
+ }
+ if (O->act == act_var) {
+ if (O->data == *X) {
+ struct tl_combinator_tree *R = tl_tree_dup (Y);
+ if (O->type == type_num || O->type == type_num_value) { R->type_flags += O->type_flags; }
+ return R;
+ }
+ }
+ struct tl_combinator_tree *t;
+ t = change_first_var (O->left, X, Y);
+ if (!t) { return 0;}
+ if (t == (void *)-1l) {
+ t = change_first_var (O->right, X, Y);
+ if (!t) { return 0;}
+ if (t == (void *)-1l) { return (void *)-1l; }
+ if (t != (void *)-2l) { return t;}
+ return (void *)-1l;
+ }
+ if (t != (void *)-2l) {
+ O->left = t;
+ }
+ t = change_first_var (O->right, X, Y);
+ if (!t) { return 0;}
+ if (t == (void *)-1l) {
+ return O->left;
+ }
+ if (t != (void *)-2l) {
+ O->right = t;
+ }
+ return O;
+}
+
+
+int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T);
+struct tree_var_value **_T;
+int __tok;
+void check_nat_val (struct tl_var_value v) {
+ if (!__tok) { return; }
+ long long x = v.num_val;
+ struct tl_combinator_tree *L = v.val;
+ if (L->type == type_type) { return;}
+ while (1) {
+ if (L->type == type_num_value) {
+ if (x + L->type_flags < 0) {
+ __tok = 0;
+ return;
+ } else {
+ return;
+ }
+ }
+ assert (L->type == type_num);
+ x += L->type_flags;
+ x += tl_get_var_value_num (_T, L->data);
+ L = tl_get_var_value (_T, L->data);
+ if (!L) { return;}
+ }
+}
+
+int check_constructors_equal (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T) {
+ if (!uniformize (L, R, T)) { return 0; }
+ __tok = 1;
+ _T = T;
+ tree_act_var_value (*T, check_nat_val);
+ return __tok;
+}
+
+struct tl_combinator_tree *reduce_type (struct tl_combinator_tree *A, struct tl_type *t) {
+ assert (A);
+ if (A->type_len == t->params_num) {
+ assert (A->type_flags == t->params_types);
+ A->act = act_type;
+ A->type = type_type;
+ A->left = A->right = 0;
+ A->data = t;
+ return A;
+ }
+ A->left = reduce_type (A->left, t);
+ return A;
+}
+
+struct tl_combinator_tree *change_value_var (struct tl_combinator_tree *O, struct tree_var_value **X) {
+ if (!O) { return (void *)-2l; };
+ while (O->act == act_var) {
+ assert (O->data);
+ if (!tl_get_var_value (X, O->data)) {
+ break;
+ }
+ if (O->type == type_type) {
+ O = tl_tree_dup (tl_get_var_value (X, O->data));
+ } else {
+ long long n = tl_get_var_value_num (X, O->data);
+ struct tl_combinator_tree *T = tl_get_var_value (X, O->data);
+ O->data = T->data;
+ O->type = T->type;
+ O->act = T->act;
+ O->type_flags = O->type_flags + n + T->type_flags;
+ }
+ }
+ if (O->act == act_field) {
+ if (tl_get_var_value (X, O)) { return (void *)-1l; }
+ }
+ struct tl_combinator_tree *t;
+ t = change_value_var (O->left, X);
+ if (!t) { return 0;}
+ if (t == (void *)-1l) {
+ t = change_value_var (O->right, X);
+ if (!t) { return 0;}
+ if (t == (void *)-1l) { return (void *)-1l; }
+ if (t != (void *)-2l) { return t;}
+ return (void *)-1l;
+ }
+ if (t != (void *)-2l) {
+ O->left = t;
+ }
+ t = change_value_var (O->right, X);
+ if (!t) { return 0;}
+ if (t == (void *)-1l) {
+ return O->left;
+ }
+ if (t != (void *)-2l) {
+ O->right = t;
+ }
+ return O;
+}
+
+int tl_parse_partial_type_app_decl (struct tree *T) {
+ assert (T->type == type_partial_type_app_decl);
+ assert (T->nc >= 1);
+
+ assert (T->c[0]->type == type_boxed_type_ident);
+ struct tl_type *t = tl_get_type (T->c[0]->text, T->c[0]->len);
+ if (!t) {
+ TL_ERROR ("Can not make partial app for unknown type\n");
+ return 0;
+ }
+
+ tl_type_finalize (t);
+
+ struct tl_combinator_tree *L = tl_parse_ident (T->c[0], 0);
+ assert (L);
+ int i;
+ tl_buf_reset ();
+ int cc = T->nc - 1;
+ for (i = 1; i < T->nc; i++) {
+ TL_TRY (tl_parse_any_term (T->c[i], 0), L);
+ tl_buf_add_tree (L->right, 1);
+ }
+
+ while (L->type_len) {
+ struct tl_combinator_tree *C = alloc_ctree_node ();
+ C->act = act_var;
+ C->type = (L->type_flags & 1) ? type_num : type_type;
+ C->type_len = 0;
+ C->type_flags = 0;
+ C->data = (void *)-1l;
+ L = tl_union (L, C);
+ if (!L) { return 0; }
+ }
+
+
+ static char _buf[100000];
+ snprintf (_buf, 100000, "%s%.*s", t->id, buf_pos, buf);
+ struct tl_type *nt = tl_add_type (_buf, strlen (_buf), t->params_num - cc, t->params_types >> cc);
+ assert (nt);
+ //snprintf (_buf, 100000, "%s #", t->id);
+ //nt->real_id = strdup (_buf);
+
+ for (i = 0; i < t->constructors_num; i++) {
+ struct tl_constructor *c = t->constructors[i];
+ struct tree_var_value *V = 0;
+ TL_INIT (A);
+ TL_INIT (B);
+ A = tl_tree_dup (c->left);
+ B = tl_tree_dup (c->right);
+
+ struct tree_var_value *W = 0;
+ change_var_ptrs (c->left, A, &W);
+ change_var_ptrs (c->right, B, &W);
+
+
+ if (!check_constructors_equal (B, L, &V)) { continue; }
+ B = reduce_type (B, nt);
+ A = change_value_var (A, &V);
+ if (A == (void *)-1l) { A = 0;}
+ B = change_value_var (B, &V);
+ assert (B != (void *)-1l);
+ snprintf (_buf, 100000, "%s%.*s", c->id, buf_pos, buf);
+
+ struct tl_constructor *r = tl_add_constructor (nt, _buf, strlen (_buf), 1);
+ snprintf (_buf, 100000, "%s", c->id);
+ r->real_id = tstrdup (_buf);
+
+ r->left = A;
+ r->right = B;
+ if (!r->name) {
+ tl_count_combinator_name (r);
+ }
+ tl_print_combinator (r);
+ }
+
+ return 1;
+}
+
+int tl_parse_partial_comb_app_decl (struct tree *T, int fun) {
+ assert (T->type == type_partial_comb_app_decl);
+
+ struct tl_constructor *c = !fun ? tl_get_constructor (T->c[0]->text, T->c[0]->len) : tl_get_function (T->c[0]->text, T->c[0]->len);
+ if (!c) {
+ TL_ERROR ("Can not make partial app for undefined combinator\n");
+ return 0;
+ }
+
+ //TL_INIT (K);
+ //static char buf[1000];
+ //int x = sprintf (buf, "%s", c->id);
+ TL_INIT (L);
+ TL_INIT (R);
+ L = tl_tree_dup (c->left);
+ R = tl_tree_dup (c->right);
+
+
+ struct tree_var_value *V = 0;
+ change_var_ptrs (c->left, L, &V);
+ change_var_ptrs (c->right, R, &V);
+ V = tree_clear_var_value (V);
+
+ int i;
+ tl_buf_reset ();
+ for (i = 1; i < T->nc; i++) {
+ TL_INIT (X);
+ TL_INIT (Z);
+ X = tl_parse_any_term (T->c[i], 0);
+ struct tl_combinator_tree *K = 0;
+ if (!(Z = change_first_var (L, &K, X))) {
+ TL_FAIL;
+ }
+ L = Z;
+ if (!K) {
+ TL_ERROR ("Partial app: not enougth variables (i = %d)\n", i);
+ TL_FAIL;
+ }
+ if (!(Z = change_first_var (R, &K, X))) {
+ TL_FAIL;
+ }
+ assert (Z == R);
+ tl_buf_add_tree (X, 1);
+ }
+
+ static char _buf[100000];
+ snprintf (_buf, 100000, "%s%.*s", c->id, buf_pos, buf);
+// fprintf (stderr, "Local id: %s\n", _buf);
+
+ struct tl_constructor *r = !fun ? tl_add_constructor (c->type, _buf, strlen (_buf), 1) : tl_add_function (c->type, _buf, strlen (_buf), 1);
+ r->left = L;
+ r->right = R;
+ snprintf (_buf, 100000, "%s", c->id);
+ r->real_id = tstrdup (_buf);
+ if (!r->name) {
+ tl_count_combinator_name (r);
+ }
+ tl_print_combinator (r);
+ return 1;
+}
+
+
+int tl_parse_partial_app_decl (struct tree *T, int fun) {
+ assert (T->type == type_partial_app_decl);
+ assert (T->nc == 1);
+ if (T->c[0]->type == type_partial_comb_app_decl) {
+ return tl_parse_partial_comb_app_decl (T->c[0], fun);
+ } else {
+ if (fun) {
+ TL_ERROR ("Partial type app in functions block\n");
+ TL_FAIL;
+ }
+ return tl_parse_partial_type_app_decl (T->c[0]);
+ }
+}
+
+int tl_parse_final_final (struct tree *T) {
+ assert (T->type == type_final_final);
+ assert (T->nc == 1);
+ struct tl_type *R;
+ if ((R = tl_get_type (T->c[0]->text, T->c[0]->len))) {
+ R->flags |= 1;
+ return 1;
+ } else {
+ TL_ERROR ("Final statement for type `%.*s` before declaration\n", T->c[0]->len, T->c[0]->text);
+ TL_FAIL;
+ }
+}
+
+int tl_parse_final_new (struct tree *T) {
+ assert (T->type == type_final_new);
+ assert (T->nc == 1);
+ if (tl_get_type (T->c[0]->text, T->c[0]->len)) {
+ TL_ERROR ("New statement: type `%.*s` already declared\n", T->c[0]->len, T->c[0]->text);
+ TL_FAIL;
+ } else {
+ return 1;
+ }
+}
+
+int tl_parse_final_empty (struct tree *T) {
+ assert (T->type == type_final_empty);
+ assert (T->nc == 1);
+ if (tl_get_type (T->c[0]->text, T->c[0]->len)) {
+ TL_ERROR ("New statement: type `%.*s` already declared\n", T->c[0]->len, T->c[0]->text);
+ TL_FAIL;
+ }
+ struct tl_type *t = tl_add_type (T->c[0]->text, T->c[0]->len, 0, 0);
+ assert (t);
+ t->flags |= 1 | FLAG_EMPTY;
+ return 1;
+}
+
+int tl_parse_final_decl (struct tree *T, int fun) {
+ assert (T->type == type_final_decl);
+ assert (!fun);
+ assert (T->nc == 1);
+ switch (T->c[0]->type) {
+ case type_final_new:
+ return tl_parse_final_new (T->c[0]);
+ case type_final_final:
+ return tl_parse_final_final (T->c[0]);
+ case type_final_empty:
+ return tl_parse_final_empty (T->c[0]);
+ default:
+ assert (0);
+ return 0;
+ }
+}
+
+int tl_parse_builtin_combinator_decl (struct tree *T, int fun) {
+ if (fun) {
+ TL_ERROR ("Builtin type can not be described in function block\n");
+ return -1;
+ }
+ assert (T->type == type_builtin_combinator_decl);
+ assert (T->nc == 2);
+ assert (T->c[0]->type == type_full_combinator_id);
+ assert (T->c[1]->type == type_boxed_type_ident);
+
+
+ if ((!mystrcmp2 (T->c[0]->text, T->c[0]->len, "int") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Int")) ||
+ (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "long") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Long")) ||
+ (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "double") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Double")) ||
+ (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "string") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "String"))) {
+ struct tl_type *t = tl_add_type (T->c[1]->text, T->c[1]->len, 0, 0);
+ if (!t) {
+ return 0;
+ }
+ struct tl_constructor *c = tl_add_constructor (t, T->c[0]->text, T->c[0]->len, 0);
+ if (!c) {
+ return 0;
+ }
+
+ c->left = alloc_ctree_node ();
+ c->left->act = act_question_mark;
+ c->left->type = type_list_item;
+
+ c->right = alloc_ctree_node ();
+ c->right->act = act_type;
+ c->right->data = t;
+ c->right->type = type_type;
+
+ if (!c->name) {
+ tl_count_combinator_name (c);
+ }
+ tl_print_combinator (c);
+ } else {
+ TL_ERROR ("Unknown builting type `%.*s`\n", T->c[0]->len, T->c[0]->text);
+ return 0;
+ }
+
+ return 1;
+}
+
+int tl_parse_declaration (struct tree *T, int fun) {
+ assert (T->type == type_declaration);
+ assert (T->nc == 1);
+ switch (T->c[0]->type) {
+ case type_combinator_decl:
+ return tl_parse_combinator_decl (T->c[0], fun);
+ case type_partial_app_decl:
+ return tl_parse_partial_app_decl (T->c[0], fun);
+ case type_final_decl:
+ return tl_parse_final_decl (T->c[0], fun);
+ case type_builtin_combinator_decl:
+ return tl_parse_builtin_combinator_decl (T->c[0], fun);
+ default:
+ assert (0);
+ return 0;
+ }
+}
+
+int tl_parse_constr_declarations (struct tree *T) {
+ assert (T->type == type_constr_declarations);
+ int i;
+ for (i = 0; i < T->nc; i++) {
+ TL_TRY_PES (tl_parse_declaration (T->c[i], 0));
+ }
+ return 1;
+}
+
+int tl_parse_fun_declarations (struct tree *T) {
+ assert (T->type == type_fun_declarations);
+ int i;
+ for (i = 0; i < T->nc; i++) {
+ TL_TRY_PES (tl_parse_declaration (T->c[i], 1));
+ }
+ return 1;
+}
+
+int tl_tree_lookup_value (struct tl_combinator_tree *L, void *var, struct tree_var_value **T) {
+ if (!L) {
+ return -1;
+ }
+ if (L->act == act_var && L->data == var) {
+ return 0;
+ }
+ if (L->act == act_var) {
+ struct tl_combinator_tree *E = tl_get_var_value (T, L->data);
+ if (!E) { return -1;}
+ else { return tl_tree_lookup_value (E, var, T); }
+ }
+ if (tl_tree_lookup_value (L->left, var, T) >= 0) { return 1; }
+ if (tl_tree_lookup_value (L->right, var, T) >= 0) { return 1; }
+ return -1;
+}
+
+int tl_tree_lookup_value_nat (struct tl_combinator_tree *L, void *var, long long x, struct tree_var_value **T) {
+ assert (L);
+ if (L->type == type_num_value) { return -1; }
+ assert (L->type == type_num);
+ assert (L->act == act_var);
+ if (L->data == var) {
+ return x == L->type_flags ? 0 : 1;
+ } else {
+ if (!tl_get_var_value (T, L->data)) {
+ return -1;
+ }
+ return tl_tree_lookup_value_nat (tl_get_var_value (T, L->data), var, x + tl_get_var_value_num (T, L->data), T);
+ }
+
+}
+
+int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T) {
+ if (!L || !R) {
+ assert (!L && !R);
+ return 1;
+ }
+ if (R->act == act_var) {
+ struct tl_combinator_tree *_ = R; R = L; L = _;
+ }
+
+ if (L->type == type_type) {
+ if (R->type != type_type || L->type_len != R->type_len || L->type_flags != R->type_flags) {
+ return 0;
+ }
+ if (R->data == (void *)-1l || L->data == (void *)-1l) { return 1;}
+ if (L->act == act_var) {
+ int x = tl_tree_lookup_value (R, L->data, T);
+ if (x > 0) {
+// if (tl_tree_lookup_value (R, L->data, T) > 0) {
+ return 0;
+ }
+ if (x == 0) {
+ return 1;
+ }
+ struct tl_combinator_tree *E = tl_get_var_value (T, L->data);
+ if (!E) {
+ tl_set_var_value (T, L->data, R);
+ return 1;
+ } else {
+ return uniformize (E, R, T);
+ }
+ } else {
+ if (L->act != R->act || L->data != R->data) {
+ return 0;
+ }
+ return uniformize (L->left, R->left, T) && uniformize (L->right, R->right, T);
+ }
+ } else {
+ assert (L->type == type_num || L->type == type_num_value);
+ if (R->type != type_num && R->type != type_num_value) {
+ return 0;
+ }
+ assert (R->type == type_num || R->type == type_num_value);
+ if (R->data == (void *)-1l || L->data == (void *)-1l) { return 1;}
+ long long x = 0;
+ struct tl_combinator_tree *K = L;
+ while (1) {
+ x += K->type_flags;
+ if (K->type == type_num_value) {
+ break;
+ }
+ if (!tl_get_var_value (T, K->data)) {
+ int s = tl_tree_lookup_value_nat (R, K->data, K->type_flags, T);
+ if (s > 0) {
+ return 0;
+ }
+ if (s == 0) {
+ return 1;
+ }
+ /*tl_set_var_value_num (T, K->data, R, -x);
+ return 1;*/
+ break;
+ }
+ x += tl_get_var_value_num (T, K->data);
+ K = tl_get_var_value (T, K->data);
+ }
+ long long y = 0;
+ struct tl_combinator_tree *M = R;
+ while (1) {
+ y += M->type_flags;
+ if (M->type == type_num_value) {
+ break;
+ }
+ if (!tl_get_var_value (T, M->data)) {
+ int s = tl_tree_lookup_value_nat (L, M->data, M->type_flags, T);
+ if (s > 0) {
+ return 0;
+ }
+ if (s == 0) {
+ return 1;
+ }
+ /*tl_set_var_value_num (T, M->data, L, -y);
+ return 1;*/
+ break;
+ }
+ y += tl_get_var_value_num (T, M->data);
+ M = tl_get_var_value (T, M->data);
+ }
+ if (K->type == type_num_value && M->type == type_num_value) {
+ return x == y;
+ }
+ if (M->type == type_num_value) {
+ tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags));
+ return 1;
+ } else if (K->type == type_num_value) {
+ tl_set_var_value_num (T, M->data, K, -(y - x + K->type_flags));
+ return 1;
+ } else {
+ if (x >= y) {
+ tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags));
+ } else {
+ tl_set_var_value_num (T, M->data, K, -(y - x + K->type_flags));
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+void tl_type_check (struct tl_type *t) {
+ if (!__ok) return;
+ if (!strcmp (t->id, "#")) { t->name = 0x70659eff; return; }
+ if (!strcmp (t->id, "Type")) { t->name = 0x2cecf817; return; }
+ if (t->constructors_num <= 0 && !(t->flags & FLAG_EMPTY)) {
+ TL_ERROR ("Type %s has no constructors\n", t->id);
+ __ok = 0;
+ return;
+ }
+ int i, j;
+ t->name = 0;
+ for (i = 0; i < t->constructors_num; i++) {
+ t->name ^= t->constructors[i]->name;
+ }
+ for (i = 0; i < t->constructors_num; i++) {
+ for (j = i + 1; j < t->constructors_num; j++) {
+ struct tree_var_value *v = 0;
+ if (check_constructors_equal (t->constructors[i]->right, t->constructors[j]->right, &v)) {
+ t->flags |= 16;
+ }
+ }
+ }
+ if ((t->flags & 24) == 24) {
+ TL_WARNING ("Warning: Type %s has overlapping costructors, but it is used with `%%`\n", t->id);
+ }
+ int z = 0;
+ int sid = 0;
+ for (i = 0; i < t->constructors_num; i++) if (*t->constructors[i]->id == '_') {
+ z ++;
+ sid = i;
+ }
+ if (z > 1) {
+ TL_ERROR ("Type %s has %d default constructors\n", t->id, z);
+ __ok = 0;
+ return;
+ }
+ if (z == 1 && (t->flags & 8)) {
+ TL_ERROR ("Type %s has default constructors and used bare\n", t->id);
+ __ok = 0;
+ return;
+ }
+ if (z) {
+ struct tl_constructor *c;
+ c = t->constructors[sid];
+ t->constructors[sid] = t->constructors[t->constructors_num - 1];
+ t->constructors[t->constructors_num - 1] = c;
+ }
+}
+
+struct tl_program *tl_parse (struct tree *T) {
+ assert (T);
+ assert (T->type == type_tl_program);
+ int i;
+ tl_program_cur = talloc (sizeof (*tl_program_cur));
+ tl_add_type ("#", 1, 0, 0);
+ tl_add_type ("Type", 4, 0, 0);
+ for (i = 0; i < T->nc; i++) {
+ if (T->c[i]->type == type_constr_declarations) { TL_TRY_PES (tl_parse_constr_declarations (T->c[i])); }
+ else { TL_TRY_PES (tl_parse_fun_declarations (T->c[i])) }
+ }
+ __ok = 1;
+ tree_act_tl_type (tl_type_tree, tl_type_check);
+ if (!__ok) {
+ return 0;
+ }
+ return tl_program_cur;
+}
+
+int __f;
+int num = 0;
+
+void wint (int a) {
+// printf ("%d ", a);
+ a = htole32 (a);
+ assert (write (__f, &a, 4) == 4);
+}
+
+void wdata (const void *x, int len) {
+ assert (write (__f, x, len) == len);
+}
+
+void wstr (const char *s) {
+ if (s) {
+// printf ("\"%s\" ", s);
+ int x = strlen (s);
+ if (x <= 254) {
+ unsigned char x_c = (unsigned char)x;
+ assert (write (__f, &x_c, 1) == 1);
+ } else {
+ fprintf (stderr, "String is too big...\n");
+ assert (0);
+ }
+ wdata (s, x);
+ x ++; // The header, containing the length, which is 1 byte
+ int t = 0;
+ if (x & 3) {
+ // Let's hope it's truly zero on every platform
+ wdata (&t, 4 - (x & 3));
+ }
+ } else {
+// printf ("<none> ");
+ wint (0);
+ }
+}
+
+void wll (long long a) {
+// printf ("%lld ", a);
+ a = htole64 (a);
+ assert (write (__f, &a, 8) == 8);
+}
+
+int count_list_size (struct tl_combinator_tree *T) {
+ assert (T->type == type_list || T->type == type_list_item);
+ if (T->type == type_list_item) {
+ return 1;
+ } else {
+ return count_list_size (T->left) + count_list_size (T->right);
+ }
+}
+
+void write_type_flags (long long flags) {
+ int new_flags = 0;
+ if (flags & 1) {
+ new_flags |= FLAG_BARE;
+ }
+ if (flags & FLAG_DEFAULT_CONSTRUCTOR) {
+ new_flags |= FLAG_DEFAULT_CONSTRUCTOR;
+ }
+ wint (new_flags);
+}
+
+void write_field_flags (long long flags) {
+ int new_flags = 0;
+ //fprintf (stderr, "%lld\n", flags);
+ if (flags & 1) {
+ new_flags |= FLAG_BARE;
+ }
+ if (flags & 32) {
+ new_flags |= FLAG_OPT_VAR;
+ }
+ if (flags & FLAG_EXCL) {
+ new_flags |= FLAG_EXCL;
+ }
+ if (flags & FLAG_OPT_FIELD) {
+ // new_flags |= FLAG_OPT_FIELD;
+ new_flags |= 2;
+ }
+ if (flags & (1 << 21)) {
+ new_flags |= 4;
+ }
+ wint (new_flags);
+}
+
+void write_var_type_flags (long long flags) {
+ int new_flags = 0;
+ if (flags & 1) {
+ new_flags |= FLAG_BARE;
+ }
+ if (new_flags & FLAG_BARE) {
+ TL_ERROR ("Sorry, bare vars are not (yet ?) supported.\n");
+ assert (!(new_flags & FLAG_BARE));
+ }
+ wint (new_flags);
+}
+
+void write_tree (struct tl_combinator_tree *T, int extra, struct tree_var_value **v, int *last_var);
+void write_args (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) {
+ assert (T->type == type_list || T->type == type_list_item);
+ if (T->type == type_list) {
+ assert (T->act == act_union);
+ assert (T->left);
+ assert (T->right);
+ write_args (T->left, v, last_var);
+ write_args (T->right, v, last_var);
+ return;
+ }
+ wint (TLS_ARG_V2);
+ assert (T->act == act_field);
+ assert (T->left);
+ wstr (T->data && strcmp (T->data, "_") ? T->data : 0);
+ long long f = T->flags;
+ if (T->left->act == act_opt_field) {
+ f |= (1 << 20);
+ }
+ if (T->left->act == act_type && T->left->data && (!strcmp (((struct tl_type *)T->left->data)->id, "#") || !strcmp (((struct tl_type *)T->left->data)->id, "Type"))) {
+ write_field_flags (f | (1 << 21));
+ wint (*last_var);
+ *last_var = (*last_var) + 1;
+ tl_set_var_value_num (v, T, 0, (*last_var) - 1);
+ } else {
+ write_field_flags (f);
+ }
+ write_tree (T->left, 0, v, last_var);
+}
+
+void write_array (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) {
+ wint (TLS_ARRAY);
+ write_tree (T->left, 0, v, last_var);
+ write_tree (T->right, 0, v, last_var);
+}
+
+void write_type_rec (struct tl_combinator_tree *T, int cc, struct tree_var_value **v, int *last_var) {
+ if (T->act == act_arg) {
+ write_type_rec (T->left, cc + 1, v, last_var);
+ if (T->right->type == type_num_value || T->right->type == type_num) {
+ wint (TLS_EXPR_NAT);
+ } else {
+ wint (TLS_EXPR_TYPE);
+ }
+ write_tree (T->right, 0, v, last_var);
+ } else {
+ assert (T->act == act_var || T->act == act_type);
+ if (T->act == act_var) {
+ assert (!cc);
+ wint (TLS_TYPE_VAR);
+ wint (tl_get_var_value_num (v, T->data));
+ write_var_type_flags (T->flags);
+ //wint (T->flags);
+ } else {
+ wint (TLS_TYPE_EXPR);
+ struct tl_type *t = T->data;
+ wint (t->name);
+ write_type_flags (T->flags);
+// wint (T->flags);
+ wint (cc);
+// fprintf (stderr, "cc = %d\n", cc);
+ }
+ }
+}
+
+void write_opt_type (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) {
+ wint (tl_get_var_value_num (v, T->left->data));
+ wint (T->left->type_flags);
+// write_tree (T->right, 0, v, last_var);
+ assert (T);
+ T = T->right;
+ switch (T->type) {
+ case type_type:
+ if (T->act == act_array) {
+ write_array (T, v, last_var);
+ } else if (T->act == act_type || T->act == act_var || T->act == act_arg) {
+ write_type_rec (T, 0, v, last_var);
+ } else {
+ assert (0);
+ }
+ break;
+ default:
+ assert (0);
+ }
+}
+
+void write_tree (struct tl_combinator_tree *T, int extra, struct tree_var_value **v, int *last_var) {
+ assert (T);
+ switch (T->type) {
+ case type_list_item:
+ case type_list:
+ if (extra) {
+ wint (TLS_COMBINATOR_RIGHT_V2);
+ }
+ wint (count_list_size (T));
+ write_args (T, v, last_var);
+ break;
+ case type_num_value:
+ wint ((int)TLS_NAT_CONST);
+ wint (T->type_flags);
+ break;
+ case type_num:
+ wint ((int)TLS_NAT_VAR);
+ wint (T->type_flags);
+ wint (tl_get_var_value_num (v, T->data));
+ break;
+ case type_type:
+ if (T->act == act_array) {
+ write_array (T, v, last_var);
+ } else if (T->act == act_type || T->act == act_var || T->act == act_arg) {
+ write_type_rec (T, 0, v, last_var);
+ } else {
+ assert (T->act == act_opt_field);
+ write_opt_type (T, v, last_var);
+ }
+ break;
+ default:
+ assert (0);
+ }
+}
+
+void write_type (struct tl_type *t) {
+ wint (TLS_TYPE);
+ wint (t->name);
+ wstr (t->id);
+ wint (t->constructors_num);
+ wint (t->flags);
+ wint (t->params_num);
+ wll (t->params_types);
+}
+
+int is_builtin_type (const char *id) {
+ return !strcmp (id, "int") || !strcmp (id, "long") || !strcmp (id, "double") || !strcmp (id, "string");
+}
+
+void write_combinator (struct tl_constructor *c) {
+ wint (c->name);
+ wstr (c->id);
+ wint (c->type ? c->type->name : 0);
+ struct tree_var_value *T = 0;
+ int x = 0;
+ assert (c->right);
+ if (c->left) {
+ if (is_builtin_type (c->id)) {
+ wint (TLS_COMBINATOR_LEFT_BUILTIN);
+ } else {
+ wint (TLS_COMBINATOR_LEFT);
+ // FIXME: What is that?
+// wint (count_list_size (c->left));
+ write_tree (c->left, 0, &T, &x);
+ }
+ } else {
+ wint (TLS_COMBINATOR_LEFT);
+ wint (0);
+ }
+ wint (TLS_COMBINATOR_RIGHT_V2);
+ write_tree (c->right, 1, &T, &x);
+}
+
+void write_constructor (struct tl_constructor *c) {
+ wint (TLS_COMBINATOR);
+ write_combinator (c);
+}
+
+void write_function (struct tl_constructor *c) {
+ wint (TLS_COMBINATOR);
+ write_combinator (c);
+}
+
+void write_type_constructors (struct tl_type *t) {
+ int i;
+ for (i = 0; i < t->constructors_num; i++) {
+ write_constructor (t->constructors[i]);
+ }
+}
+
+void write_types (int f) {
+ __f = f;
+ wint (TLS_SCHEMA_V2);
+ wint (0);
+#ifdef TL_PARSER_NEED_TIME
+ wint (time (0));
+#else
+ /* Make the tlo reproducible by default. Rationale: https://wiki.debian.org/ReproducibleBuilds/Howto#Introduction */
+ wint (0);
+#endif
+ num = 0;
+ wint (total_types_num);
+ tree_act_tl_type (tl_type_tree, write_type);
+ wint (total_constructors_num);
+ tree_act_tl_type (tl_type_tree, write_type_constructors);
+ wint (total_functions_num);
+ tree_act_tl_constructor (tl_function_tree, write_function);
+}
diff --git a/tl-parser/tl-parser.h b/tl-parser/tl-parser.h
new file mode 100644
index 0000000..faa142b
--- /dev/null
+++ b/tl-parser/tl-parser.h
@@ -0,0 +1,206 @@
+/*
+ This file is part of tgl-libary/tlc
+
+ Tgl-library/tlc is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ Tgl-library/tlc 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this tgl-library/tlc. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright Vitaly Valtman 2014
+
+ It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/)
+ Copyright 2012-2013 Vkontakte Ltd
+ 2012-2013 Vitaliy Valtman
+
+*/
+
+#ifndef __TL_PARSER_NEW_H__
+#define __TL_PARSER_NEW_H__
+enum lex_type {
+ lex_error,
+ lex_char,
+ lex_triple_minus,
+ lex_uc_ident,
+ lex_lc_ident,
+ lex_eof,
+ lex_final,
+ lex_new,
+ lex_none,
+ lex_num,
+ lex_empty
+};
+
+
+struct curlex {
+ char *ptr;
+ int len;
+ enum lex_type type;
+ int flags;
+};
+
+struct parse {
+ char *text;
+ int pos;
+ int len;
+ int line;
+ int line_pos;
+ struct curlex lex;
+};
+
+
+enum tree_type {
+ type_tl_program,
+ type_fun_declarations,
+ type_constr_declarations,
+ type_declaration,
+ type_combinator_decl,
+ type_equals,
+ type_partial_app_decl,
+ type_final_decl,
+ type_full_combinator_id,
+ type_opt_args,
+ type_args,
+ type_args1,
+ type_args2,
+ type_args3,
+ type_args4,
+ type_boxed_type_ident,
+ type_subexpr,
+ type_partial_comb_app_decl,
+ type_partial_type_app_decl,
+ type_final_new,
+ type_final_final,
+ type_final_empty,
+// type_type,
+ type_var_ident,
+ type_var_ident_opt,
+ type_multiplicity,
+ type_type_term,
+ type_term,
+ type_percent,
+ type_result_type,
+ type_expr,
+ type_nat_term,
+ type_combinator_id,
+ type_nat_const,
+ type_type_ident,
+ type_builtin_combinator_decl,
+ type_exclam,
+ type_optional_arg_def
+};
+
+struct tree {
+ char *text;
+ int len;
+ enum tree_type type;
+ int lex_line;
+ int lex_line_pos;
+ int flags;
+ int size;
+ int nc;
+ struct tree **c;
+};
+
+
+#define TL_ACT(x) (x == act_var ? "act_var" : x == act_field ? "act_field" : x == act_plus ? "act_plus" : x == act_type ? "act_type" : x == act_nat_const ? "act_nat_const" : x == act_array ? "act_array" : x == act_question_mark ? "act_question_mark" : \
+ x == act_union ? "act_union" : x == act_arg ? "act_arg" : x == act_opt_field ? "act_opt_field" : "act_unknown")
+
+#define TL_TYPE(x) (x == type_num ? "type_num" : x == type_type ? "type_type" : x == type_list_item ? "type_list_item" : x == type_list ? "type_list" : x == type_num_value ? "type_num_value" : "type_unknown")
+enum combinator_tree_action {
+ act_var,
+ act_field,
+ act_plus,
+ act_type,
+ act_nat_const,
+ act_array,
+ act_question_mark,
+ act_union,
+ act_arg,
+ act_opt_field
+};
+
+enum combinator_tree_type {
+ type_num,
+ type_num_value,
+ type_type,
+ type_list_item,
+ type_list
+};
+
+struct tl_combinator_tree {
+ enum combinator_tree_action act;
+ struct tl_combinator_tree *left, *right;
+ char *name;
+ void *data;
+ long long flags;
+ enum combinator_tree_type type;
+ int type_len;
+ long long type_flags;
+};
+
+
+struct tl_program {
+ int types_num;
+ int functions_num;
+ int constructors_num;
+ struct tl_type **types;
+ struct tl_function **functions;
+// struct tl_constuctor **constructors;
+};
+
+struct tl_type {
+ char *id;
+ char *print_id;
+ char *real_id;
+ unsigned name;
+ int flags;
+
+ int params_num;
+ long long params_types;
+
+ int constructors_num;
+ struct tl_constructor **constructors;
+};
+
+struct tl_constructor {
+ char *id;
+ char *print_id;
+ char *real_id;
+ unsigned name;
+ struct tl_type *type;
+
+ struct tl_combinator_tree *left;
+ struct tl_combinator_tree *right;
+};
+
+struct tl_var {
+ char *id;
+ struct tl_combinator_tree *ptr;
+ int type;
+ int flags;
+};
+
+struct parse *tl_init_parse_file (const char *fname);
+struct tree *tl_parse_lex (struct parse *P);
+void tl_print_parse_error (void);
+struct tl_program *tl_parse (struct tree *T);
+
+void write_types (int f);
+
+#define FLAG_BARE 1
+#define FLAG_OPT_VAR (1 << 17)
+#define FLAG_EXCL (1 << 18)
+#define FLAG_OPT_FIELD (1 << 20)
+#define FLAG_IS_VAR (1 << 21)
+#define FLAG_DEFAULT_CONSTRUCTOR (1 << 25)
+#define FLAG_EMPTY (1 << 10)
+
+#endif
diff --git a/tl-parser/tl-tl.h b/tl-parser/tl-tl.h
new file mode 100644
index 0000000..8bc0a70
--- /dev/null
+++ b/tl-parser/tl-tl.h
@@ -0,0 +1,55 @@
+/*
+ This file is part of VK/KittenPHP-DB-Engine.
+
+ VK/KittenPHP-DB-Engine is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ VK/KittenPHP-DB-Engine 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VK/KittenPHP-DB-Engine. If not, see <http://www.gnu.org/licenses/>.
+
+ This program is released under the GPL with the additional exemption
+ that compiling, linking, and/or using OpenSSL is allowed.
+ You are free to remove this exemption from derived works.
+
+ Copyright 2012-2013 Vkontakte Ltd
+ 2012-2013 Vitaliy Valtman
+*/
+
+#ifndef __TL_TL_H__
+#define __TL_TL_H__
+
+// Current tl-tl schema is V2
+// See https://core.telegram.org/mtproto/TL-tl
+
+#define TLS_SCHEMA_V2 0x3a2f9be2
+#define TLS_TYPE 0x12eb4386
+#define TLS_COMBINATOR 0x5c0a1ed5
+#define TLS_COMBINATOR_LEFT_BUILTIN 0xcd211f63
+#define TLS_COMBINATOR_LEFT 0x4c12c6d9
+#define TLS_COMBINATOR_RIGHT_V2 0x2c064372
+#define TLS_ARG_V2 0x29dfe61b
+
+#define TLS_EXPR_TYPE 0xecc9da78
+#define TLS_EXPR_NAT 0xdcb49bd8
+
+#define TLS_NAT_CONST 0xdcb49bd8
+#define TLS_NAT_VAR 0x4e8a14f0
+#define TLS_TYPE_VAR 0x0142ceae
+#define TLS_ARRAY 0xd9fb20de
+#define TLS_TYPE_EXPR 0xc1863d08
+
+/* Deprecated (old versions), read-only */
+#define TLS_TREE_NAT_CONST 0xc09f07d7
+#define TLS_TREE_NAT_VAR 0x90ea6f58
+#define TLS_TREE_TYPE_VAR 0x1caa237a
+#define TLS_TREE_ARRAY 0x80479360
+#define TLS_TREE_TYPE 0x10f32190
+
+#endif
diff --git a/tl-parser/tlc.c b/tl-parser/tlc.c
new file mode 100644
index 0000000..cd0300f
--- /dev/null
+++ b/tl-parser/tlc.c
@@ -0,0 +1,165 @@
+/*
+ This file is part of tl-parser
+
+ tl-parser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ tl-parser 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this tl-parser. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright Vitaly Valtman 2014
+
+ It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/)
+ Copyright 2012-2013 Vkontakte Ltd
+ 2012-2013 Vitaliy Valtman
+
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "tl-parser.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <signal.h>
+#include "config.h"
+
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+#include <stdarg.h>
+
+int verbosity;
+int output_expressions;
+void usage (void) {
+ printf ("usage: tl-parser [-v] [-h] <TL-schema-file>\n"
+ "\tTL compiler\n"
+ "\t-v\toutput statistical and debug information into stderr\n"
+ "\t-E\twhenever is possible output to stdout expressions\n"
+ "\t-e <file>\texport serialized schema to file\n"
+ );
+ exit (2);
+}
+
+int vkext_write (const char *filename) {
+ int f = open (filename, O_CREAT | O_WRONLY | O_TRUNC, 0640);
+ assert (f >= 0);
+ write_types (f);
+ close (f);
+ return 0;
+}
+
+void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+void logprintf (const char *format __attribute__ ((unused)), ...) {
+ va_list ap;
+ va_start (ap, format);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
+}
+
+void hexdump (int *in_ptr, int *in_end) {
+ int *ptr = in_ptr;
+ while (ptr < in_end) { printf (" %08x", *(ptr ++)); }
+ printf ("\n");
+}
+
+#ifdef HAVE_EXECINFO_H
+void print_backtrace (void) {
+ void *buffer[255];
+ const int calls = backtrace (buffer, sizeof (buffer) / sizeof (void *));
+ backtrace_symbols_fd (buffer, calls, 1);
+}
+#else
+void print_backtrace (void) {
+ if (write (1, "No libexec. Backtrace disabled\n", 32) < 0) {
+ // Sad thing
+ }
+}
+#endif
+
+void sig_segv_handler (int signum __attribute__ ((unused))) {
+ if (write (1, "SIGSEGV received\n", 18) < 0) {
+ // Sad thing
+ }
+ print_backtrace ();
+ exit (EXIT_FAILURE);
+}
+
+void sig_abrt_handler (int signum __attribute__ ((unused))) {
+ if (write (1, "SIGABRT received\n", 18) < 0) {
+ // Sad thing
+ }
+ print_backtrace ();
+ exit (EXIT_FAILURE);
+}
+
+int main (int argc, char **argv) {
+ signal (SIGSEGV, sig_segv_handler);
+ signal (SIGABRT, sig_abrt_handler);
+ int i;
+ char *vkext_file = 0;
+ while ((i = getopt (argc, argv, "Ehve:w:")) != -1) {
+ switch (i) {
+ case 'E':
+ output_expressions++;
+ break;
+ case 'h':
+ usage ();
+ return 2;
+ case 'e':
+ vkext_file = optarg;
+ break;
+ case 'v':
+ verbosity++;
+ break;
+ }
+ }
+
+ if (argc != optind + 1) {
+ usage ();
+ }
+
+
+ struct parse *P = tl_init_parse_file (argv[optind]);
+ if (!P) {
+ return 0;
+ }
+ struct tree *T;
+ if (!(T = tl_parse_lex (P))) {
+ fprintf (stderr, "Error in parse:\n");
+ tl_print_parse_error ();
+ return 0;
+ } else {
+ if (verbosity) {
+ fprintf (stderr, "Parse ok\n");
+ }
+ if (!tl_parse (T)) {
+ if (verbosity) {
+ fprintf (stderr, "Fail\n");
+ }
+ return 1;
+ } else {
+ if (verbosity) {
+ fprintf (stderr, "Ok\n");
+ }
+ }
+ }
+ if (vkext_file) {
+ vkext_write (vkext_file);
+ }
+ return 0;
+}