/* asc.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2005-2009 */

/*

Copyright (c) 2005-2009 Made to Order Software Corp.

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the
following conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial
portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*/

#include	"sswf/libsswf_as.h"

using namespace sswf;
using namespace as;

const char	version[] = "1.0";

bool		verbose, use8859_1;
const char	*output, *progname, *source;
int		errcnt, trees;
Options		options;




void usage(void)
{
	printf("%s driver version %s\n", progname, version);
	printf("Using sswf-as library version %s\n", Parser::Version());
	printf("Usage: %s [-opt] <filename>\n", progname);
	printf("  where -opt is one or more of the following:\n");
	printf("\n");
	printf("    -h or -help or --help\n");
	printf("           print out this help screen\n");
	printf("    -source <filename>\n");
	printf("           define the original filename in case you needed iconv\n");
	printf("    -o <filename>\n");
	printf("           set the output file as <filename>\n");
	printf("    -d or -debug\n");
	printf("           turn on the debug output\n");
	printf("    -dl or -debug-lexer\n");
	printf("           turn on the lexer debug output\n");
	printf("    -iso8859-1\n");
	printf("           read the input as if in ISO 8859-1\n");
	printf("    -Xo or -extended-operators\n");
	printf("           accepts min, max, match, power, rotate operators\n");
	printf("    -Xno or -no-extended-operators\n");
	printf("           refuse extended operators\n");
	printf("    -Xe or -extended-escape-sequences\n");
	printf("           accepts \\e escape sequence\n");
	printf("    -Xne or -no-extended-escape-sequence\n");
	printf("           refuse extended escape sequences\n");
	printf("    -octal\n");
	printf("           accepts octal literals (i.e. 0750)\n");
	printf("    -no-octal\n");
	printf("           refuse octal literals (ECMA version 3+)\n");
	printf("\n");
	printf("    -t #   print out different trees (add these values):\n");
	printf("           1 - parser, 2 - compile, 4 - final (and optimized)\n");
	printf("\n");
	printf("    -v     turn on the verbose mode\n");
	printf("\n");
	printf("  where <filename> is an action script source file\n");
	printf("  with the .asc extension (other files are ignored)\n");
	printf("\n");
	printf("  WARNING: the input file has to be in UCS-4 format\n");
	printf("           to be read by asc; use iconv(1) to reformat\n");
	printf("           your input file(s) as required.\n");
	printf("\n");
	exit(1);
}



int main(int argc, const char *argv[])
{
	int		i;
	NodePtr		files;

	progname = strrchr(argv[0], '/');
	if(progname == 0) {
		progname = argv[0];
	}
	else {
		progname++;
	}

	files.CreateNode(NODE_ROOT);
	options.SetOption(AS_OPTION_EXTENDED_ESCAPE_SEQUENCES, 1);
	options.SetOption(AS_OPTION_EXTENDED_OPERATORS, 1);
	options.SetOption(AS_OPTION_EXTENDED_STATEMENTS, 1);
	trees = 4;	// the final tree by default

	i = 1;
	while(i < argc) {
		if(argv[i][0] == '-' && argv[i][1] != '\0') {
			if(strcmp(argv[i], "-h") == 0
			|| strcmp(argv[i], "-help") == 0
			|| strcmp(argv[i], "--help") == 0) {
				usage();
			}
			else if(strcmp(argv[i], "-o") == 0) {
				i++;
				if(i < argc) {
					output = argv[i];
				}
			}
			else if(strcmp(argv[i], "-source") == 0) {
				i++;
				if(i < argc) {
					source = argv[i];
				}
			}
			else if(strcmp(argv[i], "-t") == 0) {
				i++;
				if(i < argc) {
					trees = atol(argv[i]);
				}
			}
			else if(strcmp(argv[i], "-debug") == 0
			|| strcmp(argv[i], "-d") == 0) {
				options.SetOption(AS_OPTION_DEBUG, 1);
			}
			else if(strcmp(argv[i], "-debug-lexer") == 0
			|| strcmp(argv[i], "-dl") == 0) {
				options.SetOption(AS_OPTION_DEBUG_LEXER, 1);
			}
			else if(strcmp(argv[i], "-iso8859-1") == 0) {
				use8859_1 = true;
			}
			else if(strcmp(argv[i], "-extended-operators") == 0
			|| strcmp(argv[i], "-Xo") == 0) {
				options.SetOption(AS_OPTION_EXTENDED_OPERATORS, 1);
			}
			else if(strcmp(argv[i], "-no-extended-operators") == 0
			|| strcmp(argv[i], "-Xno") == 0) {
				options.SetOption(AS_OPTION_EXTENDED_OPERATORS, 0);
			}
			else if(strcmp(argv[i], "-extended-statements") == 0
			|| strcmp(argv[i], "-Xs") == 0) {
				options.SetOption(AS_OPTION_EXTENDED_STATEMENTS, 1);
			}
			else if(strcmp(argv[i], "-no-extended-statements") == 0
			|| strcmp(argv[i], "-Xns") == 0) {
				options.SetOption(AS_OPTION_EXTENDED_STATEMENTS, 0);
			}
			else if(strcmp(argv[i], "-extended-escape-sequences") == 0
			|| strcmp(argv[i], "-Xe") == 0) {
				options.SetOption(AS_OPTION_EXTENDED_ESCAPE_SEQUENCES, 1);
			}
			else if(strcmp(argv[i], "-no-extended-escape-sequences") == 0
			|| strcmp(argv[i], "-Xne") == 0) {
				options.SetOption(AS_OPTION_EXTENDED_ESCAPE_SEQUENCES, 0);
			}
			else if(strcmp(argv[i], "-octal") == 0) {
				options.SetOption(AS_OPTION_OCTAL, 1);
			}
			else if(strcmp(argv[i], "-no-octal") == 0) {
				options.SetOption(AS_OPTION_OCTAL, 0);
			}
			else if(strcmp(argv[i], "-v") == 0) {
				verbose = true;
			}
			else {
				fprintf(stderr, "ERROR: unknown option \"%s\".\n", argv[i]);
				errcnt++;
			}
		}
		else {
			Parser *	parser;
			FileInput *	input;

			if(use8859_1) {
				input = new FileInput;
			}
			else {
				input = new FileUCS32Input;
			}

			const char *ext, *s;
			s = argv[i];
			ext = 0;
			while(*s != '\0') {
				if(*s == '.') {
					ext = s;
				}
				else if(*s == '/' || *s == '\\') {
					ext = 0;
					if(s[1] != '\0') {
						// dots right after / or \ mark
						// a hidden file; no extension!
						s++;
					}
				}
				s++;
			}
			if(ext != 0 && strcmp(ext, ".asc") == 0) {
				parser = Parser::CreateParser();
				parser->SetOptions(options);
				bool open = false;
				if(argv[i][0] == '-' && argv[i][1] == '\0') {
					open = input->StandardInput();
				}
				else {
					open = input->Open(argv[i]);
				}
				if(open) {
					// we use the source only once
					input->SetOriginalFilename(source);
					source = 0;
					parser->SetInput(*input);
					files.AddChild(parser->Parse());
					errcnt += input->ErrCount();
				}
				else {
					fprintf(stderr, "ERROR: can't open file \"%s\".\n", argv[i]);
					errcnt++;
				}
				delete parser;
			}
			else if(verbose) {
				fprintf(stderr, "NOTE: file \"%s\" skipped. Not ending with the proper extension (i.e. .asc).\n", argv[i]);
			}
		}
		i++;
	}

	if(errcnt != 0) {
		fprintf(stderr, "%d error%s found.\n", errcnt, errcnt == 1 ? "" : "s");
		return 1;
	}

	if(trees & 1) {
		// raw tree right after the parsing
		printf("\nRaw tree:\n");
		files.Display(stdout);
	}

// Now we're read to compile
	Compiler *compiler = Compiler::CreateCompiler(NULL);
	compiler->SetOptions(options);
	errcnt += compiler->Compile(files);

	if(trees & 2) {
		// compilation tree
		printf("\nCompiled tree:\n");
		files.Display(stdout);
	}

// Finally, we optimize the whole tree
	Optimizer *optimizer = Optimizer::CreateOptimizer();
	optimizer->SetOptions(options);
	errcnt += optimizer->Optimize(files);

	if(trees & 4) {
		// final & optimized tree
		printf("\nFinal and optimized tree:\n");
		files.Display(stdout);
	}

	if(errcnt != 0) {
#if defined(_DEBUG) || defined(DEBUG)
		fflush(stdout);
#endif
		fprintf(stderr, "%d error%s found.\n", errcnt, errcnt == 1 ? "" : "s");
		return 1;
	}

	return 0;
}

