// File: /workspace/github_c_makefile_star2_O1/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 %rdi, -0x48(%rbp)
movq %rdx, -0xa0(%rbp)
testq %rdx, %rdx
je 0x32cd
movl $0x2401, %ecx           # imm = 0x2401
xorl %ebx, %ebx
xorl %r13d, %r13d
movq -0x98(%rbp), %rax
movq %rbx, -0xa8(%rbp)
addq %rax, %rbx
xorl %r14d, %r14d
movzbl (%rbx,%r14), %eax
incq %r14
cmpl $0xd, %eax
ja 0x2e21
btl %eax, %ecx
jae 0x2e21
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 0x11cf(%rip), %rsi      # 0x402f
callq 0x11c0
testq %rax, %rax
movq %r15, -0x60(%rbp)
je 0x329f
movq %rax, %r14
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
movzbl (%r14), %ecx
cmpq $0x23, %rcx
ja 0x2eb7
movabsq $0x800002400, %rdx      # imm = 0x800002400
btq %rcx, %rdx
jb 0x329f
testq %r13, %r13
setne %cl
andb %cl, %al
cmpb $0x1, %al
jne 0x2f05
movl $0x1, %edi
movl $0x20, %esi
callq 0x1130
movq $0x0, (%rax)
movl -0x4c(%rbp), %ecx
movl %ecx, 0xc(%rax)
xorl %ecx, %ecx
cmpq -0x60(%rbp), %r14
sete %cl
addl $0x7, %ecx
movl %ecx, 0x8(%rax)
movq %r13, %rdx
movq %rdx, %rcx
movq 0x10(%rdx), %rdx
testq %rdx, %rdx
jne 0x2ef1
movq %rax, 0x10(%rcx)
movq %rcx, 0x18(%rax)
movl $0x1, %r12d
movl $0x1, %edi
movl $0x20, %esi
callq 0x1130
movq %rax, %rbx
movq %r14, %rdi
callq 0x1080
leaq 0x1(%rax), %rsi
movl $0x1, %edi
callq 0x1130
movq %rax, (%rbx)
movl -0x4c(%rbp), %eax
movl %eax, 0xc(%rbx)
movq %r14, %rdi
callq 0x1080
movq %rsp, -0x30(%rbp)
leaq 0x1(%rax), %rdx
movq %rsp, %r15
addq $0x10, %rax
andq $-0x10, %rax
subq %rax, %r15
movq %r15, %rsp
movq %r15, %rdi
xorl %esi, %esi
callq 0x10d0
movq %r14, %rdi
callq 0x1080
testq %rax, %rax
je 0x2fbb
movq %r13, -0x40(%rbp)
xorl %r12d, %r12d
xorl %r13d, %r13d
movl %r13d, %r13d
movzbl (%r14,%r13), %ecx
cmpl $0xd, %ecx
je 0x2f90
cmpl $0xa, %ecx
jne 0x2f95
incl %r13d
jmp 0x2f7e
cmpq %r13, %rax
jbe 0x2fb4
movl %r12d, %eax
movb %cl, (%r15,%rax)
incl %r12d
incl %r13d
movq %r14, %rdi
callq 0x1080
cmpq %r13, %rax
ja 0x2f7e
incl %r12d
movq -0x40(%rbp), %r13
movb $0x0, (%r15,%r12)
movq %r15, %rdi
callq 0x1080
movq (%rbx), %rdi
movq %r15, %rsi
movq %rax, -0x40(%rbp)
movq %rax, %rdx
callq 0x1160
movq %rbx, %rax
testq %r13, %r13
je 0x2ffc
movq %r13, %rcx
movq %rcx, %rax
movq 0x10(%rcx), %rcx
testq %rcx, %rcx
jne 0x2fe5
movq %rbx, 0x10(%rax)
movq %rax, 0x18(%rbx)
movq %r13, %rax
movq %rax, -0x38(%rbp)
movq (%rbx), %r13
movq 0x18(%rbx), %r12
cmpb $0x21, (%r13)
sete %cl
movq -0x40(%rbp), %rdx
cmpq $0x1, %rdx
sete %al
andb %cl, %al
testq %r12, %r12
je 0x309c
testb %al, %al
jne 0x30a0
movl 0x8(%r12), %eax
decl %eax
cmpl $0x7, %eax
ja 0x3106
leaq 0x168c(%rip), %rcx      # 0x46c8
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl $0x5, 0x8(%rbx)
movq $0x0, -0x40(%rbp)
movb $0x1, %r15b
testq %r12, %r12
je 0x30b2
movl 0x8(%r12), %eax
orl $0x4, %eax
cmpl $0x5, %eax
jne 0x30b2
movq (%r12), %rbx
movq %r13, %rdi
movq %rbx, %rsi
callq 0x1140
testq %rbx, %rbx
sete %cl
testl %eax, %eax
setne %al
orb %cl, %al
cmpb $0x1, %al
jne 0x3090
movq 0x18(%r12), %r12
jmp 0x3094
movq %r12, -0x40(%rbp)
testb %al, %al
jne 0x3054
xorl %eax, %eax
jmp 0x30b4
testb %al, %al
je 0x30a9
movl $0xb, 0x8(%rbx)
jmp 0x3123
movl $0x1, 0x8(%rbx)
jmp 0x3123
movb $0x1, %al
testb %al, %al
movq -0x38(%rbp), %r12
jne 0x3100
movl $0x200, %edx            # imm = 0x200
leaq -0x2b0(%rbp), %rbx
movq %rbx, %rdi
xorl %esi, %esi
callq 0x10d0
movq -0x40(%rbp), %rax
movq (%rax), %r8
movl $0x200, %esi            # imm = 0x200
movq %rbx, %rdi
leaq 0x1681(%rip), %rdx      # 0x4769
movq %r13, %rcx
xorl %eax, %eax
callq 0x10b0
movq -0x48(%rbp), %rdi
xorl %esi, %esi
movq %rbx, %rdx
callq 0x1628
movq -0x30(%rbp), %rbx
jmp 0x312e
cmpb $0x22, (%r15)
jne 0x3114
cmpb $0x22, -0x1(%r15,%rdx)
jne 0x315a
movq -0x48(%rbp), %rdi
movq %rbx, %rsi
movq %r15, %rdx
callq 0x2ccd
movb $0x1, %r15b
movq -0x30(%rbp), %rbx
movq -0x38(%rbp), %r12
testb %r15b, %r15b
je 0x3144
xorl %edi, %edi
leaq 0xef3(%rip), %rsi       # 0x402f
callq 0x11c0
movq %rax, %r14
movq %rbx, %rsp
xorl %eax, %eax
movq %r12, %r13
testq %r14, %r14
jne 0x2e99
jmp 0x32a2
movq %rsp, -0x80(%rbp)
movq %r14, %rcx
movq -0x60(%rbp), %rax
subq %rax, %rcx
movq %rcx, -0x78(%rbp)
subq %r14, %rax
movq -0x58(%rbp), %rcx
leaq (%rcx,%rax), %rdx
leaq (%rcx,%rax), %r12
addq $0xf, %r12
andq $-0x10, %r12
movq %rsp, %r13
movq %r13, -0x68(%rbp)
subq %r12, %r13
movq %r13, %rsp
movq %r13, %rdi
xorl %esi, %esi
callq 0x10d0
movq %r13, %rdi
movq %r15, %rsi
movq -0x40(%rbp), %rdx
callq 0x1160
movq -0x40(%rbp), %r15
movb $0x20, (%r15,%r13)
movq -0x90(%rbp), %rax
addq %r14, %rax
movq %r13, -0x70(%rbp)
addq %r13, %rax
movq -0x88(%rbp), %rcx
addq %r14, %rcx
negq %r12
movq -0x68(%rbp), %rdx
leaq (%rdx,%r12), %rsi
incq %rsi
movl $0x1, %edx
addq %rdx, %r14
leaq (%r15,%rcx), %rdi
cmpq -0x58(%rbp), %rdi
jae 0x320f
movb (%r14,%r15), %r8b
movb %r8b, (%rsi,%r15)
incq %rax
incq %rcx
incq %rsi
incq %r14
incq %rdx
cmpb $0x22, %r8b
jne 0x31e3
movb $0x0, (%rax,%r15)
addq %rdx, %r15
cmpq -0x58(%rbp), %rdi
movq -0x60(%rbp), %r14
movq -0x38(%rbp), %r12
jb 0x3235
movq -0x48(%rbp), %rdi
movl $0x1, %esi
leaq 0x1521(%rip), %rdx      # 0x4751
callq 0x1628
movq (%rbx), %rdi
callq 0x1030
leaq 0x1(%r15), %rsi
movl $0x1, %edi
callq 0x1130
movq %rax, (%rbx)
movq %rax, %rdi
movq -0x70(%rbp), %r13
movq %r13, %rsi
movq %r15, %rdx
callq 0x1160
movq -0x48(%rbp), %rdi
movq %rbx, %rsi
movq %r13, %rdx
callq 0x2ccd
movq -0x78(%rbp), %rbx
addq %r14, %rbx
movq %r13, %rdi
callq 0x1080
addq %rax, %rbx
movq %rbx, %rdi
leaq 0xda4(%rip), %rsi       # 0x402f
callq 0x11c0
movq %rax, %r14
xorl %r15d, %r15d
movq -0x80(%rbp), %rsp
jmp 0x3100
movq %r13, %r12
movq -0xa8(%rbp), %rbx
addq -0x58(%rbp), %rbx
movq -0x60(%rbp), %rdi
callq 0x1030
movq %r12, %r13
cmpq -0xa0(%rbp), %rbx
movl $0x2401, %ecx           # imm = 0x2401
jb 0x2e0d
jmp 0x32d0
xorl %r12d, %r12d
movl $0x1, %edi
movl $0x20, %esi
callq 0x1130
movl $0x9, 0x8(%rax)
testq %r12, %r12
je 0x3304
movq %r12, %rdx
movq %rdx, %rcx
movq 0x10(%rdx), %rdx
testq %rdx, %rdx
jne 0x32ee
movq %rax, 0x10(%rcx)
movq %rcx, 0x18(%rax)
jmp 0x3307
movq %rax, %r12
movq %r12, %rax
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq