// File: /workspace/github_c_makefile_star2_O3/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x288, %rsp            # imm = 0x288
movq %rsi, -0x98(%rbp)
movq %rdx, -0xa0(%rbp)
testq %rdx, %rdx
je 0x3332
movq %rdi, -0x48(%rbp)
movl $0x2401, %ecx           # imm = 0x2401
xorl %ebx, %ebx
xorl %r12d, %r12d
movq -0x98(%rbp), %rax
movq %rbx, -0xa8(%rbp)
addq %rax, %rbx
xorl %r14d, %r14d
movzbl (%rbx,%r14), %eax
incq %r14
cmpl $0xd, %eax
ja 0x2e52
btl %eax, %ecx
jae 0x2e52
leaq 0x1(%r14), %rsi
movl $0x1, %edi
callq 0x1130
movq %rax, %r15
movq %rax, %rdi
movq %rbx, %rsi
movq %r14, -0x58(%rbp)
movq %r14, %rdx
callq 0x1050
movq %r15, %rdi
leaq 0x119e(%rip), %rsi      # 0x402f
callq 0x11c0
testq %rax, %rax
je 0x32d9
movq %rax, %r13
subl %r15d, %eax
movl %eax, -0x4c(%rbp)
movq %r15, %rax
negq %rax
movq %rax, -0x90(%rbp)
movl $0x1, %eax
subq %r15, %rax
movq %rax, -0x88(%rbp)
movb $0x1, %al
movq %r15, -0x38(%rbp)
movzbl (%r13), %ecx
cmpq $0x23, %rcx
ja 0x2ee9
movabsq $0x800002400, %rdx      # imm = 0x800002400
btq %rcx, %rdx
jb 0x32d9
testq %r12, %r12
setne %cl
andb %cl, %al
cmpb $0x1, %al
jne 0x2f36
movl $0x1, %edi
movl $0x20, %esi
callq 0x1130
movq $0x0, (%rax)
movl -0x4c(%rbp), %ecx
movl %ecx, 0xc(%rax)
xorl %ecx, %ecx
cmpq %r15, %r13
sete %cl
addl $0x7, %ecx
movl %ecx, 0x8(%rax)
movq %r12, %rdx
movq %rdx, %rcx
movq 0x10(%rdx), %rdx
testq %rdx, %rdx
jne 0x2f22
movq %rax, 0x10(%rcx)
movq %rcx, 0x18(%rax)
movq %r12, -0x30(%rbp)
movl $0x1, %r14d
movl $0x1, %edi
movl $0x20, %esi
callq 0x1130
movq %rax, %r12
movq %r13, %rdi
callq 0x1080
leaq 0x1(%rax), %rsi
movl $0x1, %edi
callq 0x1130
movq %rax, (%r12)
movl -0x4c(%rbp), %eax
movl %eax, 0xc(%r12)
movq %r13, %rdi
callq 0x1080
movq %rsp, -0x40(%rbp)
leaq 0x1(%rax), %rdx
movq %rsp, %rbx
addq $0x10, %rax
andq $-0x10, %rax
subq %rax, %rbx
movq %rbx, %rsp
movq %rbx, %rdi
xorl %esi, %esi
callq 0x10d0
movq %r13, %rdi
callq 0x1080
testq %rax, %rax
je 0x2feb
xorl %r14d, %r14d
xorl %r15d, %r15d
movl %r15d, %r15d
movzbl (%r13,%r15), %ecx
cmpl $0xd, %ecx
je 0x2fc5
cmpl $0xa, %ecx
jne 0x2fca
incl %r15d
jmp 0x2fb2
cmpq %r15, %rax
jbe 0x2fe8
movl %r14d, %eax
movb %cl, (%rbx,%rax)
incl %r14d
incl %r15d
movq %r13, %rdi
callq 0x1080
cmpq %r15, %rax
ja 0x2fb2
incl %r14d
movb $0x0, (%rbx,%r14)
movq %rbx, %rdi
callq 0x1080
movq %rax, %r15
movq (%r12), %rdi
movq %rbx, %rsi
movq %rax, %rdx
callq 0x1160
movq -0x30(%rbp), %rdx
testq %rdx, %rdx
je 0x302d
movq %rdx, %rcx
movq %rcx, %rax
movq 0x10(%rcx), %rcx
testq %rcx, %rcx
jne 0x3016
movq %r12, 0x10(%rax)
movq %rax, 0x18(%r12)
jmp 0x303e
movq 0x18(%r12), %rax
movq %r12, %rdx
testq %rax, %rax
je 0x3101
movq %rdx, -0x30(%rbp)
movq (%r12), %r14
cmpb $0x21, (%r14)
jne 0x3060
cmpq $0x1, %r15
jne 0x3060
movl $0xb, 0x8(%r12)
jmp 0x3146
movl 0x8(%rax), %eax
decl %eax
cmpl $0x7, %eax
ja 0x312a
leaq 0x168f(%rip), %rcx      # 0x4704
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl $0x5, 0x8(%r12)
movq -0x38(%rbp), %r15
movq 0x18(%r12), %r12
testq %r12, %r12
je 0x30fb
movl 0x8(%r12), %eax
orl $0x4, %eax
cmpl $0x5, %eax
jne 0x30fb
movq (%r12), %rbx
movq %r14, %rdi
movq %rbx, %rsi
callq 0x1140
testq %rbx, %rbx
je 0x308b
testl %eax, %eax
jne 0x308b
movl $0x200, %edx            # imm = 0x200
leaq -0x2b0(%rbp), %rbx
movq %rbx, %rdi
xorl %esi, %esi
callq 0x10d0
movq (%r12), %r8
movl $0x200, %esi            # imm = 0x200
movq %rbx, %rdi
leaq 0x16fe(%rip), %rdx      # 0x47e1
movq %r14, %rcx
xorl %eax, %eax
callq 0x10b0
movq -0x48(%rbp), %rdi
xorl %esi, %esi
movq %rbx, %rdx
callq 0x1630
movq -0x30(%rbp), %r12
jmp 0x314e
movq (%r12), %rax
cmpb $0x21, (%rax)
movq -0x40(%rbp), %rbx
jne 0x3176
cmpq $0x1, %r15
jne 0x3176
movl $0xb, 0x8(%r12)
jmp 0x317f
movl $0x1, 0x8(%r12)
jmp 0x3146
cmpb $0x22, (%rbx)
jne 0x3137
cmpb $0x22, -0x1(%rbx,%r15)
jne 0x3185
movq -0x48(%rbp), %rdi
movq %r12, %rsi
movq %rbx, %rdx
callq 0x2d08
movq -0x30(%rbp), %r12
movq -0x38(%rbp), %r15
movq -0x40(%rbp), %rbx
xorl %edi, %edi
leaq 0xed4(%rip), %rsi       # 0x402f
callq 0x11c0
movq %rax, %r13
movq %rbx, %rsp
xorl %eax, %eax
testq %r13, %r13
jne 0x2eca
jmp 0x32d9
movl $0x1, 0x8(%r12)
movq -0x38(%rbp), %r15
jmp 0x3152
movq %rsp, -0x80(%rbp)
movq %r13, %rcx
movq -0x38(%rbp), %rax
subq %rax, %rcx
movq %rcx, -0x78(%rbp)
subq %r13, %rax
movq -0x58(%rbp), %rcx
leaq (%rcx,%rax), %rdx
addq %rcx, %rax
addq $0xf, %rax
andq $-0x10, %rax
movq %rax, -0x60(%rbp)
movq %rsp, %r14
movq %r14, -0x68(%rbp)
subq %rax, %r14
movq %r14, %rsp
movq %r14, %rdi
xorl %esi, %esi
callq 0x10d0
movq %r14, %rdi
movq %rbx, %rsi
movq %r15, %rdx
callq 0x1160
movb $0x20, (%r15,%r14)
movq -0x90(%rbp), %rax
addq %r13, %rax
movq %r14, -0x70(%rbp)
addq %r14, %rax
movq -0x88(%rbp), %rcx
addq %r13, %rcx
movq -0x60(%rbp), %rsi
negq %rsi
movq -0x68(%rbp), %rdx
addq %rsi, %rdx
incq %rdx
movl $0x1, %esi
addq %rsi, %r13
movl $0x1, %ebx
leaq (%r15,%rcx), %rsi
cmpq -0x58(%rbp), %rsi
jae 0x324a
movb (%r13,%r15), %sil
movb %sil, (%rdx,%r15)
incq %rax
incq %rcx
incq %rdx
incq %r13
incq %rbx
cmpb $0x22, %sil
jne 0x3214
movb $0x0, (%rax,%r15)
addq %rbx, %r15
movq -0x48(%rbp), %r14
jmp 0x3265
movq -0x48(%rbp), %r14
movq %r14, %rdi
movl $0x1, %esi
leaq 0x156c(%rip), %rdx      # 0x47c9
callq 0x1630
addq %rbx, %r15
movq (%r12), %rdi
callq 0x1030
leaq 0x1(%r15), %rsi
movl $0x1, %edi
callq 0x1130
movq %rax, (%r12)
movq %rax, %rdi
movq -0x70(%rbp), %r13
movq %r13, %rsi
movq %r15, %rdx
callq 0x1160
movq %r14, %rdi
movq %r12, %rsi
movq %r13, %rdx
callq 0x2d08
movq -0x38(%rbp), %r15
movq -0x78(%rbp), %rbx
addq %r15, %rbx
movq %r13, %rdi
callq 0x1080
addq %rax, %rbx
movq %rbx, %rdi
leaq 0xd6f(%rip), %rsi       # 0x402f
callq 0x11c0
movq %rax, %r13
movq -0x80(%rbp), %rsp
movq -0x30(%rbp), %r12
movq -0x40(%rbp), %rbx
jmp 0x3163
movq -0xa8(%rbp), %rbx
addq -0x58(%rbp), %rbx
movq %r15, %rdi
callq 0x1030
cmpq -0xa0(%rbp), %rbx
movl $0x2401, %ecx           # imm = 0x2401
jb 0x2e3e
movl $0x1, %edi
movl $0x20, %esi
callq 0x1130
movl $0x9, 0x8(%rax)
testq %r12, %r12
je 0x334d
movq %r12, %rdx
movq %rdx, %rcx
movq 0x10(%rdx), %rdx
testq %rdx, %rdx
jne 0x331c
movq %rax, 0x10(%rcx)
movq %rcx, 0x18(%rax)
jmp 0x3350
movl $0x1, %edi
movl $0x20, %esi
callq 0x1130
movq %rax, %r12
movl $0x9, 0x8(%rax)
jmp 0x3350
movq %rax, %r12
movq %r12, %rax
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq