// File: /workspace/github_c_makefile_star2_O0/qpfiffer[P]lair/src/parse.c
// Function: lair_tokenize
struct _lair_token *_lair_tokenize(struct _lair_runtime *r, const char *program, const size_t len) {
	struct _lair_token *tokens = NULL;
	size_t num_read = 0;

	while (num_read < len) {
		const struct _str line = read_line(program + num_read);
		num_read += line.size;
		int newline = 1;

		/* Read in a token: */
		char *token = strtok((char *)line.data, " ");
		int indentation_level = token - line.data;
		while (token != NULL) {
			/* Is it a comment? Ignore the rest of the line. */
			if (token[0] == '#') {
				break;
			} else if (_is_newline(token)) {
				break;
			}

			/* We don't want to insert an indent/dedent on the very first line,
			* and we only want to do this at the beginning of each line. The beginning
			* is basically the end though so this makes sense, right?
			*/
			if (newline != 0 && tokens != NULL) {
				/* Dedent/indent stuff. */
				struct _lair_token *new_token = calloc(1, sizeof(struct _lair_token));
				new_token->token_str = NULL;
				new_token->indent_level = indentation_level;
				if (token - line.data != 0) {
					/* line starts with spaces. */
					new_token->token_type = LR_INDENT;
				} else {
					new_token->token_type = LR_DEDENT;
				}
				_insert_token(&tokens, new_token);
			}	

			/* Create the shell of the new token and insert it. */
			struct _lair_token *new_token = calloc(1, sizeof(struct _lair_token));
			new_token->token_str = calloc(1, strlen(token) + 1);
			new_token->indent_level = indentation_level;

			/* Copy the string representation of the token into the stack. */
			const size_t new_token_len = strlen(token);
			char stripped[new_token_len + 1];
			memset(stripped, '\0', new_token_len + 1);
			_strip(token, stripped);
			const size_t stripped_len = strlen(stripped);
			memcpy(new_token->token_str, stripped, stripped_len);

			/* Actually insert it. */
			_insert_token(&tokens, new_token);

#define CALL_OR_FUNCTION if (new_token->token_str[0] == '!' && stripped_len == 1) {\
							new_token->token_type = LR_CALL;\
						} else {\
							new_token->token_type = LR_FUNCTION_DEF;\
						}

			int extra_modified = 0;
			if (new_token->prev != NULL) {
				if (new_token->token_str[0] == '!' && stripped_len == 1) {
					new_token->token_type = LR_CALL;
				} else {
					switch (new_token->prev->token_type) {
						case LR_FUNCTION_DEF:
						case LR_FUNCTION_ARG: {
							const struct _lair_token *out = NULL;
							new_token->token_type = LR_FUNCTION_ARG;
							if (_function_args_shadow_function(new_token, &out)) {
								char buf[512] = {0};
								const char *msg = "Function argument names shadow function name: %s shadows %s";
								snprintf(buf, sizeof(buf), msg, new_token->token_str, (*out).token_str);
								throw_exception(r, ERR_PARSE, buf);
							}
							break;
						}
						case LR_INDENT:
							_intuit_token_type(r, new_token, stripped);
							break;
						case LR_DEDENT:
							CALL_OR_FUNCTION
							break;
						case LR_FUNCTION_CALL:
						default:
							/* Check to see if we hit a space in the middle of a string. */
							if (stripped[0] == '"' && stripped[stripped_len - 1] != '"') {
								// TODO: Rewrite this to support multiline strings. Needs a stateful
								// variable.
								// this is a "test of the thing" okay
								// |--------->    <-----------------|
								const size_t start = token - line.data;
								const size_t end = line.size;
								char remaining[end - start];
								memset(remaining, '\0', end - start);
								memcpy(remaining, stripped, stripped_len);
								remaining[stripped_len] = ' ';
								size_t i = 0;
								size_t new_len = stripped_len + 1;
								int found_end = 0;
								for(i = stripped_len + start + 1; i < end; i++) {
									new_len++;
									remaining[i - start] = line.data[i];

									if (line.data[i] == '"') {
										remaining[i] = '\0';
										found_end = 1;
										break;
									}
								}

								if (!found_end) {
									throw_exception(r, ERR_SYNTAX, "String has no ending \".");
								}

								free(new_token->token_str);
								new_token->token_str = calloc(1, new_len + 1);
								memcpy(new_token->token_str, remaining, new_len);

								_intuit_token_type(r, new_token, remaining);

								extra_modified = 1;
								token = strtok((char *)line.data + start + strlen(remaining), " ");
							} else {
								_intuit_token_type(r, new_token, stripped);
							}
					}
				}
			} else {
				CALL_OR_FUNCTION
			}


			if (extra_modified == 0)
				token = strtok(NULL, " ");
			newline = 0;
		}

		free((char *)line.data);
	}

	struct _lair_token *eof_token = calloc(1, sizeof(struct _lair_token));
	eof_token->token_type = LR_EOF;
	_insert_token(&tokens, eof_token);

	return tokens;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x300, %rsp            # imm = 0x300
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq $0x0, -0x20(%rbp)
movq $0x0, -0x28(%rbp)
movq -0x28(%rbp), %rax
cmpq -0x18(%rbp), %rax
jae 0x4864
movq -0x10(%rbp), %rdi
addq -0x28(%rbp), %rdi
callq 0x48b0
movq %rax, -0x38(%rbp)
movq %rdx, -0x30(%rbp)
movq -0x38(%rbp), %rax
addq -0x28(%rbp), %rax
movq %rax, -0x28(%rbp)
movl $0x1, -0x3c(%rbp)
movq -0x30(%rbp), %rdi
leaq 0x1d87(%rip), %rsi      # 0x602f
callq 0x11a0
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
movq -0x30(%rbp), %rcx
subq %rcx, %rax
movl %eax, -0x4c(%rbp)
cmpq $0x0, -0x48(%rbp)
je 0x4856
movq -0x48(%rbp), %rax
movsbl (%rax), %eax
cmpl $0x23, %eax
jne 0x42db
jmp 0x4856
movq -0x48(%rbp), %rdi
callq 0x4950
cmpl $0x0, %eax
je 0x42ee
jmp 0x4856
jmp 0x42f0
cmpl $0x0, -0x3c(%rbp)
je 0x435b
cmpq $0x0, -0x20(%rbp)
je 0x435b
movl $0x1, %edi
movl $0x20, %esi
callq 0x1110
movq %rax, -0x58(%rbp)
movq -0x58(%rbp), %rax
movq $0x0, (%rax)
movl -0x4c(%rbp), %ecx
movq -0x58(%rbp), %rax
movl %ecx, 0xc(%rax)
movq -0x48(%rbp), %rax
movq -0x30(%rbp), %rcx
subq %rcx, %rax
cmpq $0x0, %rax
je 0x4343
movq -0x58(%rbp), %rax
movl $0x7, 0x8(%rax)
jmp 0x434e
movq -0x58(%rbp), %rax
movl $0x8, 0x8(%rax)
movq -0x58(%rbp), %rsi
leaq -0x20(%rbp), %rdi
callq 0x49b0
movl $0x1, %edi
movq %rdi, -0x2e8(%rbp)
movl $0x20, %esi
callq 0x1110
movq %rax, -0x60(%rbp)
movq -0x48(%rbp), %rdi
callq 0x1060
movq -0x2e8(%rbp), %rdi
movq %rax, %rsi
incq %rsi
callq 0x1110
movq %rax, %rcx
movq -0x60(%rbp), %rax
movq %rcx, (%rax)
movl -0x4c(%rbp), %ecx
movq -0x60(%rbp), %rax
movl %ecx, 0xc(%rax)
movq -0x48(%rbp), %rdi
callq 0x1060
movq %rax, -0x68(%rbp)
movq -0x68(%rbp), %rcx
movq %rcx, %rax
incq %rax
movq %rsp, %rdx
movq %rdx, -0x70(%rbp)
addq $0x10, %rcx
andq $-0x10, %rcx
movq %rsp, %rdi
subq %rcx, %rdi
movq %rdi, -0x2e0(%rbp)
movq %rdi, %rsp
movq %rax, -0x78(%rbp)
movq -0x68(%rbp), %rdx
addq $0x1, %rdx
xorl %esi, %esi
callq 0x10b0
movq -0x2e0(%rbp), %rsi
movq -0x48(%rbp), %rdi
callq 0x4a20
movq -0x2e0(%rbp), %rdi
callq 0x1060
movq -0x2e0(%rbp), %rsi
movq %rax, -0x80(%rbp)
movq -0x60(%rbp), %rax
movq (%rax), %rdi
movq -0x80(%rbp), %rdx
callq 0x1140
movq -0x60(%rbp), %rsi
leaq -0x20(%rbp), %rdi
callq 0x49b0
movl $0x0, -0x84(%rbp)
movq -0x60(%rbp), %rax
cmpq $0x0, 0x18(%rax)
je 0x47f6
movq -0x60(%rbp), %rax
movq (%rax), %rax
movsbl (%rax), %eax
cmpl $0x21, %eax
jne 0x4470
cmpq $0x1, -0x80(%rbp)
jne 0x4470
movq -0x60(%rbp), %rax
movl $0xb, 0x8(%rax)
jmp 0x47f4
movq -0x60(%rbp), %rax
movq 0x18(%rax), %rax
movl 0x8(%rax), %eax
decl %eax
movl %eax, %ecx
movq %rcx, -0x2f0(%rbp)
subl $0x7, %eax
ja 0x4582
movq -0x2f0(%rbp), %rax
leaq 0x223b(%rip), %rcx      # 0x66d8
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq $0x0, -0x90(%rbp)
movq -0x60(%rbp), %rax
movl $0x5, 0x8(%rax)
movq -0x60(%rbp), %rdi
leaq -0x90(%rbp), %rsi
callq 0x4b00
cmpl $0x0, %eax
je 0x452f
leaq -0x290(%rbp), %rdi
xorl %esi, %esi
movl $0x200, %edx            # imm = 0x200
callq 0x10b0
leaq 0x2298(%rip), %rax      # 0x6783
movq %rax, -0x298(%rbp)
leaq -0x290(%rbp), %rdi
movq -0x298(%rbp), %rdx
movq -0x60(%rbp), %rax
movq (%rax), %rcx
movq -0x90(%rbp), %rax
movq (%rax), %r8
movl $0x200, %esi            # imm = 0x200
movb $0x0, %al
callq 0x1090
movq -0x8(%rbp), %rdi
leaq -0x290(%rbp), %rdx
xorl %esi, %esi
callq 0x1870
jmp 0x47f2
movq -0x2e0(%rbp), %rdx
movq -0x8(%rbp), %rdi
movq -0x60(%rbp), %rsi
callq 0x3fa0
jmp 0x47f2
movq -0x60(%rbp), %rax
movq (%rax), %rax
movsbl (%rax), %eax
cmpl $0x21, %eax
jne 0x4570
cmpq $0x1, -0x80(%rbp)
jne 0x4570
movq -0x60(%rbp), %rax
movl $0xb, 0x8(%rax)
jmp 0x457b
movq -0x60(%rbp), %rax
movl $0x1, 0x8(%rax)
jmp 0x47f2
jmp 0x4582
movq -0x2e0(%rbp), %rax
movsbl (%rax), %eax
cmpl $0x22, %eax
jne 0x47dc
movq -0x2e0(%rbp), %rax
movq -0x80(%rbp), %rcx
subq $0x1, %rcx
movsbl (%rax,%rcx), %eax
cmpl $0x22, %eax
je 0x47dc
movq -0x48(%rbp), %rax
movq -0x30(%rbp), %rcx
subq %rcx, %rax
movq %rax, -0x2a0(%rbp)
movq -0x38(%rbp), %rax
movq %rax, -0x2a8(%rbp)
movq -0x2a8(%rbp), %rax
movq -0x2a0(%rbp), %rcx
subq %rcx, %rax
movq %rsp, %rcx
movq %rcx, -0x2b0(%rbp)
movq %rax, %rcx
addq $0xf, %rcx
andq $-0x10, %rcx
movq %rsp, %rdi
subq %rcx, %rdi
movq %rdi, -0x2f8(%rbp)
movq %rdi, %rsp
movq %rax, -0x2b8(%rbp)
movq -0x2a8(%rbp), %rdx
subq -0x2a0(%rbp), %rdx
xorl %esi, %esi
callq 0x10b0
movq -0x2e0(%rbp), %rsi
movq -0x2f8(%rbp), %rdi
movq -0x80(%rbp), %rdx
callq 0x1140
movq -0x2f8(%rbp), %rax
movq -0x80(%rbp), %rcx
movb $0x20, (%rax,%rcx)
movq $0x0, -0x2c0(%rbp)
movq -0x80(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x2c8(%rbp)
movl $0x0, -0x2cc(%rbp)
movq -0x80(%rbp), %rax
addq -0x2a0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x2c0(%rbp)
movq -0x2c0(%rbp), %rax
cmpq -0x2a8(%rbp), %rax
jae 0x4717
movq -0x2f8(%rbp), %rax
movq -0x2c8(%rbp), %rcx
addq $0x1, %rcx
movq %rcx, -0x2c8(%rbp)
movq -0x30(%rbp), %rcx
movq -0x2c0(%rbp), %rdx
movb (%rcx,%rdx), %dl
movq -0x2c0(%rbp), %rcx
subq -0x2a0(%rbp), %rcx
movb %dl, (%rax,%rcx)
movq -0x30(%rbp), %rax
movq -0x2c0(%rbp), %rcx
movsbl (%rax,%rcx), %eax
cmpl $0x22, %eax
jne 0x46fe
movq -0x2f8(%rbp), %rax
movq -0x2c0(%rbp), %rcx
movb $0x0, (%rax,%rcx)
movl $0x1, -0x2cc(%rbp)
jmp 0x4717
jmp 0x4700
movq -0x2c0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x2c0(%rbp)
jmp 0x4680
cmpl $0x0, -0x2cc(%rbp)
jne 0x4735
movq -0x8(%rbp), %rdi
movl $0x1, %esi
leaq 0x203b(%rip), %rdx      # 0x676b
callq 0x1870
movq -0x60(%rbp), %rax
movq (%rax), %rdi
callq 0x1030
movq -0x2c8(%rbp), %rsi
addq $0x1, %rsi
movl $0x1, %edi
callq 0x1110
movq -0x2f8(%rbp), %rsi
movq %rax, %rcx
movq -0x60(%rbp), %rax
movq %rcx, (%rax)
movq -0x60(%rbp), %rax
movq (%rax), %rdi
movq -0x2c8(%rbp), %rdx
callq 0x1140
movq -0x2f8(%rbp), %rdx
movq -0x8(%rbp), %rdi
movq -0x60(%rbp), %rsi
callq 0x3fa0
movq -0x2f8(%rbp), %rdi
movl $0x1, -0x84(%rbp)
movq -0x30(%rbp), %rax
addq -0x2a0(%rbp), %rax
movq %rax, -0x300(%rbp)
callq 0x1060
movq -0x300(%rbp), %rdi
addq %rax, %rdi
leaq 0x1868(%rip), %rsi      # 0x602f
callq 0x11a0
movq %rax, -0x48(%rbp)
movq -0x2b0(%rbp), %rax
movq %rax, %rsp
jmp 0x47f0
movq -0x2e0(%rbp), %rdx
movq -0x8(%rbp), %rdi
movq -0x60(%rbp), %rsi
callq 0x3fa0
jmp 0x47f2
jmp 0x47f4
jmp 0x4826
movq -0x60(%rbp), %rax
movq (%rax), %rax
movsbl (%rax), %eax
cmpl $0x21, %eax
jne 0x4819
cmpq $0x1, -0x80(%rbp)
jne 0x4819
movq -0x60(%rbp), %rax
movl $0xb, 0x8(%rax)
jmp 0x4824
movq -0x60(%rbp), %rax
movl $0x1, 0x8(%rax)
jmp 0x4826
cmpl $0x0, -0x84(%rbp)
jne 0x4843
xorl %eax, %eax
movl %eax, %edi
leaq 0x17f5(%rip), %rsi      # 0x602f
callq 0x11a0
movq %rax, -0x48(%rbp)
movl $0x0, -0x3c(%rbp)
movq -0x70(%rbp), %rax
movq %rax, %rsp
jmp 0x42bf
movq -0x30(%rbp), %rdi
callq 0x1030
jmp 0x4267
movl $0x1, %edi
movl $0x20, %esi
callq 0x1110
movq %rax, -0x2d8(%rbp)
movq -0x2d8(%rbp), %rax
movl $0x9, 0x8(%rax)
movq -0x2d8(%rbp), %rsi
leaq -0x20(%rbp), %rdi
callq 0x49b0
movq -0x20(%rbp), %rax
movq %rbp, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)