1064 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1064 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * $Id$
 | |
|  *
 | |
|     Copyright (c) 2016-2018 Chung, Hyung-Hwan. All rights reserved.
 | |
| 
 | |
|     Redistribution and use in source and binary forms, with or without
 | |
|     modification, are permitted provided that the following conditions
 | |
|     are met:
 | |
|     1. Redistributions of source code must retain the above copyright
 | |
|        notice, this list of conditions and the following disclaimer.
 | |
|     2. Redistributions in binary form must reproduce the above copyright
 | |
|        notice, this list of conditions and the following disclaimer in the
 | |
|        documentation and/or other materials provided with the distribution.
 | |
| 
 | |
|     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | |
|     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | |
|     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | |
|     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
|     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | |
|     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
|     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
|     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | |
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| #define _CRT_SECURE_NO_WARNINGS
 | |
| #endif
 | |
| 
 | |
| #include <hak.h>
 | |
| #include <hak-chr.h>
 | |
| #include <hak-cmgr.h>
 | |
| #include <hak-str.h>
 | |
| #include <hak-utl.h>
 | |
| #include <hak-opt.h>
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <limits.h>
 | |
| #include <errno.h>
 | |
| #include <locale.h>
 | |
| 
 | |
| #if defined(HAVE_ISOCLINE_H) && defined(HAVE_ISOCLINE_LIB)
 | |
| #	include <isocline.h>
 | |
| #	define USE_ISOCLINE
 | |
| #endif
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| #	include <windows.h>
 | |
| #	include <tchar.h>
 | |
| #	include <io.h>
 | |
| #	include <fcntl.h>
 | |
| #	include <time.h>
 | |
| #	include <signal.h>
 | |
| 
 | |
| #elif defined(__OS2__)
 | |
| #	define INCL_DOSMODULEMGR
 | |
| #	define INCL_DOSPROCESS
 | |
| #	define INCL_DOSERRORS
 | |
| #	include <os2.h>
 | |
| #	include <signal.h>
 | |
| 
 | |
| #elif defined(__DOS__)
 | |
| #	include <dos.h>
 | |
| #	include <time.h>
 | |
| #	include <signal.h>
 | |
| #elif defined(macintosh)
 | |
| #	include <Timer.h>
 | |
| #else
 | |
| 
 | |
| #	include <sys/types.h>
 | |
| #	include <errno.h>
 | |
| #	include <unistd.h>
 | |
| #	include <fcntl.h>
 | |
| 
 | |
| #	if defined(HAVE_TIME_H)
 | |
| #		include <time.h>
 | |
| #	endif
 | |
| #	if defined(HAVE_SYS_TIME_H)
 | |
| #		include <sys/time.h>
 | |
| #	endif
 | |
| #	if defined(HAVE_SIGNAL_H)
 | |
| #		include <signal.h>
 | |
| #	endif
 | |
| #endif
 | |
| 
 | |
| #if defined(__DOS__) || defined(_WIN32) || defined(__OS2__)
 | |
| #define FOPEN_R_FLAGS "rb"
 | |
| #else
 | |
| #define FOPEN_R_FLAGS "r"
 | |
| #endif
 | |
| 
 | |
| typedef struct xtn_t xtn_t;
 | |
| struct xtn_t
 | |
| {
 | |
| 	const char* cci_path; /* main source file */
 | |
| 	/*const char* udi_path; */ /* not implemented as of snow */
 | |
| 	const char* udo_path;
 | |
| 
 | |
| 	int vm_running;
 | |
| 
 | |
| 	struct
 | |
| 	{
 | |
| 		hak_bch_t* ptr;
 | |
| 		hak_bch_t buf[1024]; /* not used if isocline is used */
 | |
| 		hak_oow_t len;
 | |
| 		hak_oow_t pos;
 | |
| 		int eof;
 | |
| 		hak_oow_t ncompexprs; /* number of compiled expressions */
 | |
| 	} feed;
 | |
| 	/*hak_oop_t sym_errstr;*/
 | |
| };
 | |
| 
 | |
| /* ========================================================================= */
 | |
| 
 | |
| static hak_t* g_hak = HAK_NULL;
 | |
| 
 | |
| /* ========================================================================= */
 | |
| 
 | |
| static int vm_startup (hak_t* hak)
 | |
| {
 | |
| 	xtn_t* xtn = (xtn_t*)hak_getxtn(hak);
 | |
| 	xtn->vm_running = 1;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void vm_cleanup (hak_t* hak)
 | |
| {
 | |
| 	xtn_t* xtn = (xtn_t*)hak_getxtn(hak);
 | |
| 	xtn->vm_running = 0;
 | |
| 
 | |
| #if defined(USE_ISOCLINE)
 | |
| 	if (xtn->feed.ptr && xtn->feed.ptr != xtn->feed.buf)
 | |
| 	{
 | |
| 		ic_free (xtn->feed.ptr);
 | |
| 		xtn->feed.ptr = HAK_NULL;
 | |
| 	}
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*
 | |
| static void vm_checkbc (hak_t* hak, hak_oob_t bcode)
 | |
| {
 | |
| }
 | |
| */
 | |
| 
 | |
| static void on_gc_hak (hak_t* hak)
 | |
| {
 | |
| 	/*xtn_t* xtn = (xtn_t*)hak_getxtn(hak);*/
 | |
| 	/*if (xtn->sym_errstr) xtn->sym_errstr = hak_moveoop(hak, xtn->sym_errstr);*/
 | |
| }
 | |
| 
 | |
| /* ========================================================================= */
 | |
| 
 | |
| static int handle_logopt (hak_t* hak, const hak_bch_t* logstr)
 | |
| {
 | |
| 	const hak_bch_t* cm, * flt;
 | |
| 	hak_bitmask_t logmask;
 | |
| 	hak_oow_t tlen, i;
 | |
| 	hak_bcs_t fname;
 | |
| 
 | |
| 	static struct
 | |
| 	{
 | |
| 		const char* name;
 | |
| 		int op; /* 0: bitwise-OR, 1: bitwise-AND */
 | |
| 		hak_bitmask_t mask;
 | |
| 	} xtab[] =
 | |
| 	{
 | |
| 		{ "",           0, 0 },
 | |
| 
 | |
| 		{ "app",        0, HAK_LOG_APP },
 | |
| 		{ "compiler",   0, HAK_LOG_COMPILER },
 | |
| 		{ "vm",         0, HAK_LOG_VM },
 | |
| 		{ "mnemonic",   0, HAK_LOG_MNEMONIC },
 | |
| 		{ "gc",         0, HAK_LOG_GC },
 | |
| 		{ "ic",         0, HAK_LOG_IC },
 | |
| 		{ "primitive",  0, HAK_LOG_PRIMITIVE },
 | |
| 
 | |
| 		/* select a specific level */
 | |
| 		{ "fatal",      0, HAK_LOG_FATAL },
 | |
| 		{ "error",      0, HAK_LOG_ERROR },
 | |
| 		{ "warn",       0, HAK_LOG_WARN },
 | |
| 		{ "info",       0, HAK_LOG_INFO },
 | |
| 		{ "debug",      0, HAK_LOG_DEBUG },
 | |
| 
 | |
| 		/* select a specific level or higher */
 | |
| 		{ "fatal+",     0, HAK_LOG_FATAL },
 | |
| 		{ "error+",     0, HAK_LOG_FATAL | HAK_LOG_ERROR },
 | |
| 		{ "warn+",      0, HAK_LOG_FATAL | HAK_LOG_ERROR | HAK_LOG_WARN },
 | |
| 		{ "info+",      0, HAK_LOG_FATAL | HAK_LOG_ERROR | HAK_LOG_WARN | HAK_LOG_INFO },
 | |
| 		{ "debug+",     0, HAK_LOG_FATAL | HAK_LOG_ERROR | HAK_LOG_WARN | HAK_LOG_INFO | HAK_LOG_DEBUG },
 | |
| 
 | |
| 		/* select a specific level or lower */
 | |
| 		{ "fatal-",     0, HAK_LOG_FATAL | HAK_LOG_ERROR | HAK_LOG_WARN | HAK_LOG_INFO | HAK_LOG_DEBUG },
 | |
| 		{ "error-",     0, HAK_LOG_ERROR | HAK_LOG_WARN | HAK_LOG_INFO | HAK_LOG_DEBUG },
 | |
| 		{ "warn-",      0, HAK_LOG_WARN | HAK_LOG_INFO | HAK_LOG_DEBUG },
 | |
| 		{ "info-",      0, HAK_LOG_INFO | HAK_LOG_DEBUG },
 | |
| 		{ "debug-",     0, HAK_LOG_DEBUG },
 | |
| 
 | |
| 		/* exclude a specific level */
 | |
| 		{ "-fatal",     1, ~(hak_bitmask_t)HAK_LOG_FATAL },
 | |
| 		{ "-error",     1, ~(hak_bitmask_t)HAK_LOG_ERROR },
 | |
| 		{ "-warn",      1, ~(hak_bitmask_t)HAK_LOG_WARN },
 | |
| 		{ "-info",      1, ~(hak_bitmask_t)HAK_LOG_INFO },
 | |
| 		{ "-debug",     1, ~(hak_bitmask_t)HAK_LOG_DEBUG },
 | |
| 	};
 | |
| 
 | |
| 	cm = hak_find_bchar_in_bcstr(logstr, ',');
 | |
| 	if (cm)
 | |
| 	{
 | |
| 		fname.len = cm - logstr;
 | |
| 		logmask = 0;
 | |
| 
 | |
| 		do
 | |
| 		{
 | |
| 			flt = cm + 1;
 | |
| 
 | |
| 			cm = hak_find_bchar_in_bcstr(flt, ',');
 | |
| 			tlen = (cm)? (cm - flt): hak_count_bcstr(flt);
 | |
| 
 | |
| 			for (i = 0; i < HAK_COUNTOF(xtab); i++)
 | |
| 			{
 | |
| 				if (hak_comp_bchars_bcstr(flt, tlen, xtab[i].name) == 0)
 | |
| 				{
 | |
| 					if (xtab[i].op) logmask &= xtab[i].mask;
 | |
| 					else logmask |= xtab[i].mask;
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (i >= HAK_COUNTOF(xtab))
 | |
| 			{
 | |
| 				fprintf(stderr, "ERROR: unrecognized value  - [%.*s] - [%s]\n", (int)tlen, flt, logstr);
 | |
| 				return -1;
 | |
| 			}
 | |
| 		}
 | |
| 		while (cm);
 | |
| 
 | |
| 
 | |
| 		if (!(logmask & HAK_LOG_ALL_TYPES)) logmask |= HAK_LOG_ALL_TYPES;  /* no types specified. force to all types */
 | |
| 		if (!(logmask & HAK_LOG_ALL_LEVELS)) logmask |= HAK_LOG_ALL_LEVELS;  /* no levels specified. force to all levels */
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		logmask = HAK_LOG_ALL_LEVELS | HAK_LOG_ALL_TYPES;
 | |
| 		fname.len = hak_count_bcstr(logstr);
 | |
| 	}
 | |
| 
 | |
| 	fname.ptr = (hak_bch_t*)logstr;
 | |
| 	hak_setoption (hak, HAK_LOG_TARGET_BCS, &fname);
 | |
| 	hak_setoption (hak, HAK_LOG_MASK, &logmask);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| #if defined(HAK_BUILD_DEBUG)
 | |
| static int handle_dbgopt (hak_t* hak, const hak_bch_t* str)
 | |
| {
 | |
| 	/*xtn_t* xtn = (xtn_t*)hak_getxtn(hak);*/
 | |
| 	const hak_bch_t* cm, * flt;
 | |
| 	hak_oow_t len;
 | |
| 	hak_bitmask_t trait, dbgopt = 0;
 | |
| 
 | |
| 	cm = str - 1;
 | |
| 	do
 | |
| 	{
 | |
| 		flt = cm + 1;
 | |
| 
 | |
| 		cm = hak_find_bchar_in_bcstr(flt, ',');
 | |
| 		len = cm? (cm - flt): hak_count_bcstr(flt);
 | |
| 		if (len == 0) continue;
 | |
| 		else if (hak_comp_bchars_bcstr(flt, len, "gc") == 0) dbgopt |= HAK_TRAIT_DEBUG_GC;
 | |
| 		else if (hak_comp_bchars_bcstr(flt, len, "bigint") == 0) dbgopt |= HAK_TRAIT_DEBUG_BIGINT;
 | |
| 		else
 | |
| 		{
 | |
| 			fprintf(stderr, "ERROR: unknown debug option value - %.*s\n", (int)len, flt);
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 	while (cm);
 | |
| 
 | |
| 	hak_getoption(hak, HAK_TRAIT, &trait);
 | |
| 	trait |= dbgopt;
 | |
| 	hak_setoption(hak, HAK_TRAIT, &trait);
 | |
| 	return 0;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /* ========================================================================= */
 | |
| 
 | |
| #if defined(_WIN32) || defined(__DOS__) || defined(__OS2__) || defined(macintosh)
 | |
| typedef void(*signal_handler_t)(int);
 | |
| #elif defined(macintosh)
 | |
| typedef void(*signal_handler_t)(int); /* TODO: */
 | |
| #elif defined(SA_SIGINFO)
 | |
| typedef void(*signal_handler_t)(int, siginfo_t*, void*);
 | |
| #else
 | |
| typedef void(*signal_handler_t)(int);
 | |
| #endif
 | |
| 
 | |
| 
 | |
| #if defined(_WIN32) || defined(__DOS__) || defined(__OS2__)
 | |
| static void handle_sigint (int sig)
 | |
| {
 | |
| 	if (g_hak) hak_abort (g_hak);
 | |
| }
 | |
| #elif defined(macintosh)
 | |
| /* TODO */
 | |
| #elif defined(SA_SIGINFO)
 | |
| static void handle_sigint (int sig, siginfo_t* siginfo, void* ctx)
 | |
| {
 | |
| 	if (g_hak) hak_abort (g_hak);
 | |
| }
 | |
| #else
 | |
| static void handle_sigint (int sig)
 | |
| {
 | |
| 	if (g_hak) hak_abort (g_hak);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static void set_signal (int sig, signal_handler_t handler)
 | |
| {
 | |
| #if defined(_WIN32) || defined(__DOS__) || defined(__OS2__)
 | |
| 	signal (sig, handler);
 | |
| #elif defined(macintosh)
 | |
| 	/* TODO: implement this */
 | |
| #else
 | |
| 	struct sigaction sa;
 | |
| 
 | |
| 	memset (&sa, 0, sizeof(sa));
 | |
| 	/*sa.sa_handler = handler;*/
 | |
| #if defined(SA_SIGINFO)
 | |
| 	sa.sa_flags = SA_SIGINFO;
 | |
| 	sa.sa_sigaction = handler;
 | |
| #else
 | |
| 	sa.sa_handler = handler;
 | |
| #endif
 | |
| 	sigemptyset (&sa.sa_mask);
 | |
| 
 | |
| 	sigaction (sig, &sa, NULL);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static void set_signal_to_default (int sig)
 | |
| {
 | |
| #if defined(_WIN32) || defined(__DOS__) || defined(__OS2__)
 | |
| 	signal (sig, SIG_DFL);
 | |
| #elif defined(macintosh)
 | |
| 	/* TODO: implement this */
 | |
| #else
 | |
| 	struct sigaction sa;
 | |
| 
 | |
| 	memset (&sa, 0, sizeof(sa));
 | |
| 	sa.sa_handler = SIG_DFL;
 | |
| 	sa.sa_flags = 0;
 | |
| 	sigemptyset (&sa.sa_mask);
 | |
| 
 | |
| 	sigaction (sig, &sa, NULL);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* ========================================================================= */
 | |
| 
 | |
| static void print_info (void)
 | |
| {
 | |
| #if defined(HAK_CONFIGURE_CMD) && defined(HAK_CONFIGURE_ARGS)
 | |
| 	printf("Configured with: %s %s\n", HAK_CONFIGURE_CMD, HAK_CONFIGURE_ARGS);
 | |
| #elif defined(_WIN32)
 | |
| 	printf("Built for windows\n");
 | |
| #else
 | |
| 	/* TODO: improve this part */
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static void print_synerr (hak_t* hak)
 | |
| {
 | |
| 	hak_synerr_t synerr;
 | |
| 	xtn_t* xtn;
 | |
| 
 | |
| 	xtn = (xtn_t*)hak_getxtn(hak);
 | |
| 	hak_getsynerr(hak, &synerr);
 | |
| 
 | |
| 	hak_logbfmt(hak,HAK_LOG_STDERR, "ERROR: ");
 | |
| 	if (synerr.loc.file)
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDERR, "%js", synerr.loc.file);
 | |
| 	else
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDERR, "%hs", xtn->cci_path);
 | |
| 
 | |
| 	hak_logbfmt(hak, HAK_LOG_STDERR, "[%zu,%zu] %js",
 | |
| 		synerr.loc.line, synerr.loc.colm,
 | |
| 		(hak_geterrmsg(hak) != hak_geterrstr(hak)? hak_geterrmsg(hak): hak_geterrstr(hak))
 | |
| 	);
 | |
| 
 | |
| 	hak_logbfmt(hak, HAK_LOG_STDERR, "\n");
 | |
| }
 | |
| 
 | |
| static void print_other_error (hak_t* hak)
 | |
| {
 | |
| 	xtn_t* xtn;
 | |
| 	hak_loc_t loc;
 | |
| 
 | |
| 	xtn = (xtn_t*)hak_getxtn(hak);
 | |
| 	hak_geterrloc(hak, &loc);
 | |
| 
 | |
| 	hak_logbfmt(hak,HAK_LOG_STDERR, "ERROR: ");
 | |
| 	if (loc.file)
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDERR, "%js", loc.file);
 | |
| 	else
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDERR, "%hs", xtn->cci_path);
 | |
| 
 | |
| 	hak_logbfmt(hak, HAK_LOG_STDERR, "[%zu,%zu] %js", loc.line, loc.colm, hak_geterrmsg(hak));
 | |
| 
 | |
| 	hak_logbfmt(hak, HAK_LOG_STDERR, "\n");
 | |
| }
 | |
| 
 | |
| static void print_error (hak_t* hak, const hak_bch_t* msghdr)
 | |
| {
 | |
| 	if (HAK_ERRNUM(hak) == HAK_ESYNERR) print_synerr(hak);
 | |
| 	else print_other_error(hak);
 | |
| 	/*else hak_logbfmt(hak, HAK_LOG_STDERR, "ERROR: %hs - [%d] %js\n", msghdr, hak_geterrnum(hak), hak_geterrmsg(hak));*/
 | |
| }
 | |
| 
 | |
| 
 | |
| #if defined(USE_ISOCLINE)
 | |
| static void print_incomplete_expression_error (hak_t* hak)
 | |
| {
 | |
| 	/* isocline is supposed to return a full expression.
 | |
| 	 * if something is pending in the feed side, the input isn't complete yet */
 | |
| 	xtn_t* xtn;
 | |
| 	hak_loc_t loc;
 | |
| 
 | |
| 	xtn = hak_getxtn(hak);
 | |
| 	hak_getfeedloc (hak, &loc);
 | |
| 
 | |
| 	hak_logbfmt(hak, HAK_LOG_STDERR, "ERROR: ");
 | |
| 	if (loc.file)
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDERR, "%js", loc.file);
 | |
| 	else
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDERR, "%hs", xtn->cci_path);
 | |
| 
 | |
| 	/* if the input is like this
 | |
| 	 *   a := 2; c := {
 | |
| 	 * the second expression is incompelete. however, the whole input is not executed.
 | |
| 	 * the number of compiled expressions so far is in xtn->feed.ncompexprs, however */
 | |
| 	hak_logbfmt(hak, HAK_LOG_STDERR, "[%zu,%zu] incomplete expression\n", loc.line, loc.colm);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static void show_prompt (hak_t* hak, int level)
 | |
| {
 | |
| /* TODO: different prompt per level */
 | |
| 	hak_resetfeedloc (hak); /* restore the line number to 1 in the interactive mode */
 | |
| #if !defined(USE_ISOCLINE)
 | |
| 	hak_logbfmt(hak, HAK_LOG_STDOUT, "HAK> ");
 | |
| 	hak_logbfmt(hak, HAK_LOG_STDOUT, HAK_NULL); /* flushing */
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static hak_oop_t execute_in_interactive_mode (hak_t* hak)
 | |
| {
 | |
| 	hak_oop_t retv;
 | |
| 
 | |
| 	hak_decode (hak, hak_getcode(hak), 0, hak_getbclen(hak));
 | |
| 	HAK_LOG0 (hak, HAK_LOG_MNEMONIC, "------------------------------------------\n");
 | |
| 	g_hak = hak;
 | |
| 	/*setup_tick ();*/
 | |
| 
 | |
| 	retv = hak_execute(hak);
 | |
| 
 | |
| 	/* flush pending output data in the interactive mode(e.g. printf without a newline) */
 | |
| 	hak_flushudio (hak);
 | |
| 
 | |
| 	if (!retv)
 | |
| 	{
 | |
| 		print_error(hak, "execute");
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		/* print the result in the interactive mode regardless 'verbose' */
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDOUT, "%O\n", retv); /* TODO: show this go to the output handler?? */
 | |
| 		/*
 | |
| 		 * print the value of ERRSTR.
 | |
| 		hak_oop_cons_t cons = hak_getatsysdic(hak, xtn->sym_errstr);
 | |
| 		if (cons)
 | |
| 		{
 | |
| 			HAK_ASSERT(hak, HAK_IS_CONS(hak, cons));
 | |
| 			HAK_ASSERT(hak, HAK_CONS_CAR(cons) == xtn->sym_errstr);
 | |
| 			hak_print (hak, HAK_CONS_CDR(cons));
 | |
| 		}
 | |
| 		*/
 | |
| 	}
 | |
| 	/*cancel_tick();*/
 | |
| 	g_hak = HAK_NULL;
 | |
| 
 | |
| 	return retv;
 | |
| }
 | |
| 
 | |
| static hak_oop_t execute_in_batch_mode(hak_t* hak, int verbose)
 | |
| {
 | |
| 	hak_oop_t retv;
 | |
| 
 | |
| 	hak_decode(hak, hak_getcode(hak), 0, hak_getbclen(hak));
 | |
| 	HAK_LOG3(hak, HAK_LOG_MNEMONIC, "BYTECODES bclen=%zu lflen=%zu ngtmprs=%zu\n", hak_getbclen(hak), hak_getlflen(hak), hak_getngtmprs(hak));
 | |
| 	g_hak = hak;
 | |
| 	/*setup_tick ();*/
 | |
| 
 | |
| 
 | |
| /* TESTING */
 | |
| #if 0
 | |
| {
 | |
| 	hak_code_t xcode;
 | |
| 	hak_ptlc_t mem;
 | |
| 
 | |
| 	memset(&xcode, 0, HAK_SIZEOF(xcode));
 | |
| 	memset(&mem, 0, HAK_SIZEOF(mem));
 | |
| 
 | |
| 	hak_marshalcodetomem(hak, &hak->code, &mem);
 | |
| 	hak_unmarshalcodefrommem(hak, &xcode, (const hak_ptl_t*)&mem);
 | |
| 	hak_freemem(hak, mem.ptr);
 | |
| 
 | |
| 	hak_decode(hak, &xcode, 0, xcode.bc.len);
 | |
| 	hak_purgecode(hak, &xcode);
 | |
| }
 | |
| #endif
 | |
| /* END TESTING */
 | |
| 
 | |
| 	retv = hak_execute(hak);
 | |
| 	hak_flushudio (hak);
 | |
| 
 | |
| 	if (!retv) print_error(hak, "execute");
 | |
| 	else if (verbose) hak_logbfmt(hak, HAK_LOG_STDERR, "EXECUTION OK - EXITED WITH %O\n", retv);
 | |
| 
 | |
| 	/*cancel_tick();*/
 | |
| 	g_hak = HAK_NULL;
 | |
| 	/*hak_dumpsymtab (hak);*/
 | |
| 
 | |
| 	return retv;
 | |
| }
 | |
| 
 | |
| static int on_fed_cnode_in_interactive_mode (hak_t* hak, hak_cnode_t* obj)
 | |
| {
 | |
| 	xtn_t* xtn = (xtn_t*)hak_getxtn(hak);
 | |
| 	int flags = 0;
 | |
| 
 | |
| 	/* in the interactive, the compile error must not break the input loop.
 | |
| 	 * this function returns 0 to go on despite a compile-time error.
 | |
| 	 *
 | |
| 	 * if a single line or continued lines contain multiple expressions,
 | |
| 	 * execution is delayed until the last expression is compiled. */
 | |
| 
 | |
| 	if (xtn->feed.ncompexprs <= 0)
 | |
| 	{
 | |
| 		/* the first expression in the current user input line.
 | |
| 		 * arrange to clear byte-codes before compiling the expression. */
 | |
| 		flags = HAK_COMPILE_CLEAR_CODE | HAK_COMPILE_CLEAR_FUNBLK;
 | |
| 	}
 | |
| 
 | |
| 	if (hak_compile(hak, obj, flags) <= -1)
 | |
| 	{
 | |
| 		/*print_error(hak, "compile"); */
 | |
| 		xtn->feed.pos = xtn->feed.len; /* arrange to discard the rest of the line */
 | |
| 		return -1; /* this causes the feed function to fail and
 | |
| 		              the error handler to print the error message */
 | |
| 	}
 | |
| 
 | |
| 	xtn->feed.ncompexprs++;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int on_fed_cnode_in_batch_mode (hak_t* hak, hak_cnode_t* obj)
 | |
| {
 | |
| 	/*xtn_t* xtn = (xtn_t*)hak_getxtn(hak);*/
 | |
| 	return hak_compile(hak, obj, 0);
 | |
| }
 | |
| 
 | |
| #if defined(USE_ISOCLINE)
 | |
| static int get_line (hak_t* hak, xtn_t* xtn, FILE* fp)
 | |
| {
 | |
| 	char* inp;
 | |
| 	static int inited = 0;
 | |
| 
 | |
| 	if (!inited)
 | |
| 	{
 | |
| 		ic_style_def("kbd","gray underline");     // you can define your own styles
 | |
| 		ic_style_def("ic-prompt","ansi-maroon");  // or re-define system styles
 | |
| 		ic_set_history (HAK_NULL, -1);
 | |
| 		ic_enable_multiline (1);
 | |
| 		ic_enable_multiline_indent (1);
 | |
| 		ic_set_matching_braces ("()[]{}");
 | |
| 		ic_enable_brace_insertion (1);
 | |
| 		ic_set_insertion_braces("()[]{}\"\"''");
 | |
| 		inited = 1;
 | |
| 	}
 | |
| 
 | |
| 	if (xtn->feed.eof) return 0;
 | |
| 
 | |
| 	xtn->feed.pos = 0;
 | |
| 	xtn->feed.len = 0;
 | |
| 	if (xtn->feed.ptr)
 | |
| 	{
 | |
| 		HAK_ASSERT(hak, xtn->feed.ptr != xtn->feed.buf);
 | |
| 		ic_free (xtn->feed.ptr);
 | |
| 		xtn->feed.ptr = HAK_NULL;
 | |
| 	}
 | |
| 
 | |
| 	inp = ic_readline("HAK");
 | |
| 	if (inp == NULL)
 | |
| 	{
 | |
| 		/* TODO: check if it's an error or Eof */
 | |
| 		xtn->feed.eof = 1;
 | |
| 		HAK_ASSERT(hak, xtn->feed.pos == 0);
 | |
| 		HAK_ASSERT(hak, xtn->feed.len == 0);
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	xtn->feed.len = hak_count_bcstr(inp);
 | |
| 	xtn->feed.ptr = inp;
 | |
| 	return 1;
 | |
| }
 | |
| #else
 | |
| static int get_line (hak_t* hak, xtn_t* xtn, FILE* fp)
 | |
| {
 | |
| 	if (xtn->feed.eof) return 0;
 | |
| 
 | |
| 	xtn->feed.pos = 0;
 | |
| 	xtn->feed.len = 0;
 | |
| 	xtn->feed.ptr = xtn->feed.buf; /* use the internal buffer */
 | |
| 
 | |
| 	while (1)
 | |
| 	{
 | |
| 		int ch = fgetc(fp);
 | |
| 		if (ch == EOF)
 | |
| 		{
 | |
| 			if (ferror(fp))
 | |
| 			{
 | |
| 				hak_logbfmt(hak, HAK_LOG_STDERR, "ERROR: failed to read - %hs - %hs\n", xtn->cci_path, strerror(errno));
 | |
| 				return -1;
 | |
| 			}
 | |
| 
 | |
| 			xtn->feed.eof = 1;
 | |
| 			if (xtn->feed.len <= 0) return 0;
 | |
| 
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		xtn->feed.buf[xtn->feed.len++] = (hak_bch_t)(unsigned int)ch;
 | |
| 		if (ch == '\n' || xtn->feed.len >= HAK_COUNTOF(xtn->feed.buf)) break;
 | |
| 	}
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static int feed_loop (hak_t* hak, xtn_t* xtn, int verbose)
 | |
| {
 | |
| 	FILE* fp = HAK_NULL;
 | |
| 	int is_tty;
 | |
| 
 | |
| #if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__)
 | |
| 	errno_t err = fopen_s(&fp, xtn->cci_path, FOPEN_R_FLAGS);
 | |
| 	if (err != 0)
 | |
| 	{
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDERR, "ERROR: failed to open - %hs - %hs\n", xtn->cci_path, strerror(err));
 | |
| 		goto oops;
 | |
| 	}
 | |
| #else
 | |
| 	fp = fopen(xtn->cci_path, FOPEN_R_FLAGS);
 | |
| 	if (!fp)
 | |
| 	{
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDERR, "ERROR: failed to open - %hs - %hs\n", xtn->cci_path, strerror(errno));
 | |
| 		goto oops;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 	is_tty = _isatty(_fileno(fp));
 | |
| #else
 | |
| 	is_tty = isatty(fileno(fp));
 | |
| #endif
 | |
| 
 | |
| 	/* override the default cnode handler. the default one simply
 | |
| 	 * compiles the expression node without execution */
 | |
| 	/*if (hak_beginfeed(hak, is_tty? on_fed_cnode_in_interactive_mode: HAK_NULL) <= -1)*/
 | |
| 	if (hak_beginfeed(hak, is_tty? on_fed_cnode_in_interactive_mode: on_fed_cnode_in_batch_mode) <= -1)
 | |
| 	{
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDERR, "ERROR: cannot begin feed - [%d] %js\n", hak_geterrnum(hak), hak_geterrmsg(hak));
 | |
| 		goto oops;
 | |
| 	}
 | |
| 
 | |
| 	if (is_tty)
 | |
| 	{
 | |
| 		/* interactive mode */
 | |
| 		show_prompt (hak, 0);
 | |
| 
 | |
| 		while (1)
 | |
| 		{
 | |
| 			int n;
 | |
| 			hak_oow_t pos;
 | |
| 			hak_oow_t len;
 | |
| 
 | |
| 		#if defined(USE_ISOCLINE)
 | |
| 			int lf_injected = 0;
 | |
| 		#endif
 | |
| 
 | |
| 			/* read a line regardless of the actual expression */
 | |
| 			n = get_line(hak, xtn, fp);
 | |
| 			if (n <= -1) goto oops;
 | |
| 			if (n == 0) break;
 | |
| 
 | |
| 			/* feed the line */
 | |
| 			pos = xtn->feed.pos;
 | |
| 			/* update xtn->feed.pos before calling hak_feedbchars() so that the callback sees the updated value */
 | |
| 			xtn->feed.pos = xtn->feed.len;
 | |
| 			len = xtn->feed.len - pos;
 | |
| 			n = hak_feedbchars(hak, &xtn->feed.ptr[pos], len);
 | |
| 		#if defined(USE_ISOCLINE)
 | |
| 		chars_fed:
 | |
| 		#endif
 | |
| 			if (n <= -1)
 | |
| 			{
 | |
| 				print_error(hak, "feed"); /* syntax error or something - mostly compile error */
 | |
| 
 | |
| 		#if defined(USE_ISOCLINE)
 | |
| 			reset_on_feed_error:
 | |
| 		#endif
 | |
| 				hak_resetfeed(hak);
 | |
| 				hak_clearcode(hak); /* clear the compiled code but not executed yet in advance */
 | |
| 				xtn->feed.ncompexprs = 0; /* next time, on_fed_cnode_in_interactive_mode() clears code and fnblks */
 | |
| 				/*if (len > 0)*/ show_prompt(hak, 0); /* show prompt after error */
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				if (!hak_feedpending(hak))
 | |
| 				{
 | |
| 					if (xtn->feed.ncompexprs > 0)
 | |
| 					{
 | |
| 						if (hak_getbclen(hak) > 0) execute_in_interactive_mode (hak);
 | |
| 						xtn->feed.ncompexprs = 0;
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						/* usually this part is reached if the input string is
 | |
| 						 * one or more whilespaces and/or comments only.
 | |
| 						 * ------------------------------------------------------
 | |
| 						 * if the previous compiled code has not been cleared (e.g.
 | |
| 						 * hcl_compile() ever called with HCL_COMPILE_CLEAR_CODE
 | |
| 						 * or hcl_clearcode() explicitly called), hak_getbcllen(hak)
 | |
| 						 * may still return a positive number greater than 0. */
 | |
| 					}
 | |
| 					show_prompt (hak, 0); /* show prompt after execution */
 | |
| 				}
 | |
| 		#if defined(USE_ISOCLINE)
 | |
| 				else if (!lf_injected)
 | |
| 				{
 | |
| 					/* in this mode, one input string must be composed of one or more
 | |
| 					 * complete expression. however, it doesn't isocline doesn't include
 | |
| 					 * the ending line-feed in the returned input string. inject one to the feed */
 | |
| 					static const char lf = '\n';
 | |
| 					lf_injected = 1;
 | |
| 					n = hak_feedbchars(hak, &lf, 1);
 | |
| 					goto chars_fed;
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					print_incomplete_expression_error(hak);
 | |
| 					goto reset_on_feed_error;
 | |
| 				}
 | |
| 		#endif
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 	#if !defined(USE_ISOCLINE)
 | |
| 		/* eof is given, usually with ctrl-D, no new line is output after the prompt.
 | |
| 		 * this results in the OS prompt on the same line as this program's prompt.
 | |
| 		 * however ISOCLINE prints a newline upon ctrl-D. print \n when ISOCLINE is
 | |
| 		 * not used */
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDOUT, "\n");
 | |
| 	#endif
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		/* non-interactive mode */
 | |
| 		while (1)
 | |
| 		{
 | |
| 			hak_bch_t buf[1024];
 | |
| 			hak_oow_t xlen;
 | |
| 
 | |
| 			xlen = fread(buf, HAK_SIZEOF(buf[0]), HAK_COUNTOF(buf), fp);
 | |
| 			if (xlen > 0 && hak_feedbchars(hak, buf, xlen) <= -1) goto endfeed_error;
 | |
| 			if (xlen < HAK_COUNTOF(buf))
 | |
| 			{
 | |
| 				if (ferror(fp))
 | |
| 				{
 | |
| 					hak_logbfmt(hak, HAK_LOG_STDERR, "ERROR: failed to read - %hs - %hs\n", xtn->cci_path, strerror(errno));
 | |
| 					goto oops;
 | |
| 				}
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (hak_endfeed(hak) <= -1)
 | |
| 	{
 | |
| 	endfeed_error:
 | |
| 		print_error(hak, "endfeed");
 | |
| 		goto oops; /* TODO: proceed or just exit? */
 | |
| 	}
 | |
| 	fclose (fp);
 | |
| 
 | |
| 	if (!is_tty && hak_getbclen(hak) > 0) execute_in_batch_mode (hak, verbose);
 | |
| 	return 0;
 | |
| 
 | |
| oops:
 | |
| 	if (fp) fclose (fp);
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| /* #define DEFAULT_HEAPSIZE (512000ul) */
 | |
| #define DEFAULT_HEAPSIZE (0ul) /* don't use the pre-allocated heap */
 | |
| 
 | |
| int main (int argc, char* argv[])
 | |
| {
 | |
| 	hak_t* hak = HAK_NULL;
 | |
| 	xtn_t* xtn;
 | |
| 	hak_cb_t hakcb;
 | |
| 	hak_errinf_t errinf;
 | |
| 
 | |
| 	hak_bci_t c;
 | |
| 	static hak_bopt_lng_t lopt[] =
 | |
| 	{
 | |
| #if defined(HAK_BUILD_DEBUG)
 | |
| 		{ ":debug",       '\0' },
 | |
| #endif
 | |
| 		{ ":heapsize",    '\0' },
 | |
| 		{ ":log",         'l'  },
 | |
| 		{ "info",         '\0' },
 | |
| 		{ ":modlibdirs",  '\0' },
 | |
| 
 | |
| 		{ HAK_NULL,       '\0' }
 | |
| 	};
 | |
| 	static hak_bopt_t opt =
 | |
| 	{
 | |
| 		"l:v",
 | |
| 		lopt
 | |
| 	};
 | |
| 
 | |
| 	const char* logopt = HAK_NULL;
 | |
| 	hak_oow_t heapsize = DEFAULT_HEAPSIZE;
 | |
| 	int verbose = 0;
 | |
| 	int show_info = 0;
 | |
| 	const char* modlibdirs = HAK_NULL;
 | |
| 
 | |
| #if defined(HAK_BUILD_DEBUG)
 | |
| 	const char* dbgopt = HAK_NULL;
 | |
| #endif
 | |
| 
 | |
| 	setlocale(LC_ALL, "");
 | |
| 
 | |
| #if !defined(macintosh)
 | |
| 	if (argc < 2)
 | |
| 	{
 | |
| 	print_usage:
 | |
| 		fprintf(stderr, "Usage: %s [options] script-filename [output-filename]\n", argv[0]);
 | |
| 		fprintf(stderr, "Options are:\n");
 | |
| 		fprintf(stderr, " -v  show verbose messages\n");
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	while ((c = hak_getbopt(argc, argv, &opt)) != HAK_BCI_EOF)
 | |
| 	{
 | |
| 		switch (c)
 | |
| 		{
 | |
| 			case 'l':
 | |
| 				logopt = opt.arg;
 | |
| 				break;
 | |
| 
 | |
| 			case 'v':
 | |
| 				verbose = 1;
 | |
| 				break;
 | |
| 
 | |
| 			case '\0':
 | |
| 				if (hak_comp_bcstr(opt.lngopt, "heapsize") == 0)
 | |
| 				{
 | |
| 					heapsize = strtoul(opt.arg, HAK_NULL, 0);
 | |
| 					break;
 | |
| 				}
 | |
| 			#if defined(HAK_BUILD_DEBUG)
 | |
| 				else if (hak_comp_bcstr(opt.lngopt, "debug") == 0)
 | |
| 				{
 | |
| 					dbgopt = opt.arg;
 | |
| 					break;
 | |
| 				}
 | |
| 			#endif
 | |
| 				else if (hak_comp_bcstr(opt.lngopt, "info") == 0)
 | |
| 				{
 | |
| 					show_info = 1;
 | |
| 					break;
 | |
| 				}
 | |
| 				else if (hak_comp_bcstr(opt.lngopt, "modlibdirs") == 0)
 | |
| 				{
 | |
| 					modlibdirs = opt.arg;
 | |
| 					break;
 | |
| 				}
 | |
| 
 | |
| 				goto print_usage;
 | |
| 
 | |
| 			case ':':
 | |
| 				if (opt.lngopt)
 | |
| 					fprintf(stderr, "bad argument for '%s'\n", opt.lngopt);
 | |
| 				else
 | |
| 					fprintf(stderr, "bad argument for '%c'\n", opt.opt);
 | |
| 
 | |
| 				return -1;
 | |
| 
 | |
| 			default:
 | |
| 				goto print_usage;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if ((opt.ind + 1) != argc && (opt.ind + 2) != argc && !show_info) goto print_usage;
 | |
| #endif
 | |
| 
 | |
| 	hak = hak_openstd(HAK_SIZEOF(xtn_t), &errinf);
 | |
| 	if (HAK_UNLIKELY(!hak))
 | |
| 	{
 | |
| 		const hak_bch_t* msg;
 | |
| 	#if defined(HAK_OOCH_IS_UCH)
 | |
| 		hak_bch_t msgbuf[HAK_ERRMSG_CAPA];
 | |
| 		hak_oow_t msglen, wcslen;
 | |
| 		msglen = HAK_COUNTOF(msgbuf);
 | |
| 		hak_conv_ucstr_to_bcstr_with_cmgr(errinf.msg, &wcslen, msgbuf, &msglen, hak_get_cmgr_by_id(HAK_CMGR_UTF8));
 | |
| 		msg = msgbuf;
 | |
| 	#else
 | |
| 		msg = errinf.msg;
 | |
| 	#endif
 | |
| 
 | |
| 		printf("ERROR: cannot open hak - %s\n", msg);
 | |
| 		goto oops;
 | |
| 	}
 | |
| 
 | |
| 	xtn = (xtn_t*)hak_getxtn(hak);
 | |
| 
 | |
| 	{
 | |
| 		hak_oow_t tab_size;
 | |
| 		tab_size = 5000;
 | |
| 		hak_setoption (hak, HAK_SYMTAB_SIZE, &tab_size);
 | |
| 		tab_size = 5000;
 | |
| 		hak_setoption (hak, HAK_SYSDIC_SIZE, &tab_size);
 | |
| 		tab_size = 600; /* TODO: choose a better stack size or make this user specifiable */
 | |
| 		hak_setoption (hak, HAK_PROCSTK_SIZE, &tab_size);
 | |
| 	}
 | |
| 
 | |
| 	{
 | |
| 		hak_bitmask_t trait = 0;
 | |
| 
 | |
| 		/*trait |= HAK_TRAIT_NOGC;*/
 | |
| 		trait |= HAK_TRAIT_AWAIT_PROCS;
 | |
| 		trait |= HAK_TRAIT_LANG_ENABLE_EOL;
 | |
| 		hak_setoption (hak, HAK_TRAIT, &trait);
 | |
| 	}
 | |
| 
 | |
| 	if (modlibdirs)
 | |
| 	{
 | |
| 	#if defined(HAK_OOCH_IS_UCH)
 | |
| 		hak_ooch_t* tmp;
 | |
| 		tmp = hak_dupbtoucstr(hak, modlibdirs, HAK_NULL);
 | |
| 		if (HAK_UNLIKELY(!tmp))
 | |
| 		{
 | |
| 			hak_logbfmt(hak, HAK_LOG_STDERR,"ERROR: cannot duplicate modlibdirs - [%d] %js\n", hak_geterrnum(hak), hak_geterrmsg(hak));
 | |
| 			goto oops;
 | |
| 		}
 | |
| 
 | |
| 		if (hak_setoption(hak, HAK_MOD_LIBDIRS, tmp) <= -1)
 | |
| 		{
 | |
| 			hak_logbfmt(hak, HAK_LOG_STDERR,"ERROR: cannot set modlibdirs - [%d] %js\n", hak_geterrnum(hak), hak_geterrmsg(hak));
 | |
| 			hak_freemem(hak, tmp);
 | |
| 			goto oops;
 | |
| 		}
 | |
| 		hak_freemem(hak, tmp);
 | |
| 	#else
 | |
| 		if (hak_setoption(hak, HAK_MOD_LIBDIRS, modlibdirs) <= -1)
 | |
| 		{
 | |
| 			hak_logbfmt(hak, HAK_LOG_STDERR,"ERROR: cannot set modlibdirs - [%d] %js\n", hak_geterrnum(hak), hak_geterrmsg(hak));
 | |
| 			goto oops;
 | |
| 		}
 | |
| 	#endif
 | |
| 	}
 | |
| 
 | |
| 	memset (&hakcb, 0, HAK_SIZEOF(hakcb));
 | |
| 	hakcb.on_gc = on_gc_hak;
 | |
| 	hakcb.vm_startup = vm_startup;
 | |
| 	hakcb.vm_cleanup = vm_cleanup;
 | |
| 	/*hakcb.vm_checkbc = vm_checkbc;*/
 | |
| 	hak_regcb (hak, &hakcb);
 | |
| 
 | |
| 	if (logopt && handle_logopt(hak, logopt) <= -1) goto oops;
 | |
| 
 | |
| #if defined(HAK_BUILD_DEBUG)
 | |
| 	if (dbgopt && handle_dbgopt(hak, dbgopt) <= -1) goto oops;
 | |
| #endif
 | |
| 
 | |
| 	if (show_info)
 | |
| 	{
 | |
| 		print_info();
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	if (hak_ignite(hak, heapsize) <= -1)
 | |
| 	{
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDERR, "cannot ignite hak - [%d] %js\n", hak_geterrnum(hak), hak_geterrmsg(hak));
 | |
| 		goto oops;
 | |
| 	}
 | |
| 
 | |
| 	if (hak_addbuiltinprims(hak) <= -1)
 | |
| 	{
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDERR, "cannot add builtin primitives - [%d] %js\n", hak_geterrnum(hak), hak_geterrmsg(hak));
 | |
| 		goto oops;
 | |
| 	}
 | |
| 
 | |
| 	xtn->cci_path = argv[opt.ind++]; /* input source code file */
 | |
| 	if (opt.ind < argc) xtn->udo_path = argv[opt.ind++];
 | |
| 
 | |
| 	if (hak_attachcciostdwithbcstr(hak, xtn->cci_path) <= -1)
 | |
| 	{
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDERR, "ERROR: cannot attach source input stream - [%d] %js\n", hak_geterrnum(hak), hak_geterrmsg(hak));
 | |
| 		goto oops;
 | |
| 	}
 | |
| 
 | |
| 	if (hak_attachudiostdwithbcstr(hak, "", xtn->udo_path) <= -1) /* TODO: add udi path */
 | |
| 	{
 | |
| 		hak_logbfmt(hak, HAK_LOG_STDERR, "ERROR: cannot attach user data streams - [%d] %js\n", hak_geterrnum(hak), hak_geterrmsg(hak));
 | |
| 		goto oops;
 | |
| 	}
 | |
| 
 | |
| 	/* -- from this point onward, any failure leads to jumping to the oops label
 | |
| 	 * -- instead of returning -1 immediately. --*/
 | |
| 	set_signal(SIGINT, handle_sigint);
 | |
| 
 | |
| #if 0
 | |
| // TODO: change the option name
 | |
| // in the INTERACTIVE mode, the compiler generates MAKE_FUNCTION for lambda functions.
 | |
| // in the non-INTERACTIVE mode, the compiler generates MAKE_BLOCK for lambda functions.
 | |
| {
 | |
| 	hak_bitmask_t trait;
 | |
| 	hak_getoption(hak, HAK_TRAIT, &trait);
 | |
| 	trait |= HAK_TRAIT_INTERACTIVE;
 | |
| 	hak_setoption(hak, HAK_TRAIT, &trait);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| 	if (feed_loop(hak, xtn, verbose) <= -1) goto oops;
 | |
| 
 | |
| 	set_signal_to_default(SIGINT);
 | |
| 	hak_close(hak);
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| oops:
 | |
| 	set_signal_to_default(SIGINT); /* harmless to call multiple times without set_signal() */
 | |
| 	if (hak) hak_close(hak);
 | |
| 	return -1;
 | |
| }
 |