// File: /workspace/github_c_makefile_star2_O2/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 $0x278, %rsp            # imm = 0x278
movq %rdx, -0x90(%rbp)
movq %rsi, -0x88(%rbp)
leaq -0x58(%rbp), %rax
andq $0x0, (%rax)
movl $0x2401, %ecx           # imm = 0x2401
xorl %edx, %edx
movq %rdi, -0x40(%rbp)
cmpq -0x90(%rbp), %rdx
jae 0x30bd
movq -0x88(%rbp), %rax
movq %rdx, -0x68(%rbp)
leaq (%rax,%rdx), %rbx
xorl %r15d, %r15d
movzbl (%rbx,%r15), %eax
incq %r15
cmpl $0xd, %eax
ja 0x2c80
btl %eax, %ecx
jae 0x2c80
leaq 0x1(%r15), %rsi
pushq $0x1
popq %r14
movq %r14, %rdi
callq 0x1130
movq %rax, %r12
movq %rax, %rdi
movq %rbx, %rsi
movq %r15, %rdx
callq 0x1050
movq %r15, -0x60(%rbp)
addq %r15, -0x68(%rbp)
movq %r12, %rdi
leaq 0x136a(%rip), %rsi      # 0x402f
callq 0x11c0
movq %rax, %rbx
subl %r12d, %eax
movl %eax, -0x44(%rbp)
movq %r12, %rax
negq %rax
movq %rax, -0xa0(%rbp)
movq %r12, -0x50(%rbp)
subq %r12, %r14
movq %r14, -0x98(%rbp)
movb $0x1, %al
testq %rbx, %rbx
je 0x30a6
movzbl (%rbx), %ecx
cmpq $0x23, %rcx
ja 0x2d16
movabsq $0x800002400, %rdx      # imm = 0x800002400
btq %rcx, %rdx
jb 0x30a6
cmpq $0x0, -0x58(%rbp)
setne %cl
andb %cl, %al
cmpb $0x1, %al
jne 0x2d54
pushq $0x1
popq %rdi
pushq $0x20
popq %rsi
callq 0x1130
andq $0x0, (%rax)
movl -0x44(%rbp), %ecx
movl %ecx, 0xc(%rax)
xorl %ecx, %ecx
cmpq -0x50(%rbp), %rbx
sete %cl
addl $0x7, %ecx
movl %ecx, 0x8(%rax)
leaq -0x58(%rbp), %rdi
movq %rax, %rsi
callq 0x30f0
pushq $0x1
popq %r14
movq %r14, %rdi
pushq $0x20
popq %rsi
callq 0x1130
movq %rax, %r15
movq %rbx, %rdi
callq 0x1080
leaq 0x1(%rax), %rsi
movq %r14, %rdi
callq 0x1130
movq %rax, (%r15)
movl -0x44(%rbp), %eax
movq %r15, -0x30(%rbp)
movl %eax, 0xc(%r15)
movq %rbx, %rdi
callq 0x1080
movq %rsp, -0x38(%rbp)
leaq 0x1(%rax), %rdx
movq %rsp, %r14
addq $0x10, %rax
andq $-0x10, %rax
subq %rax, %r14
movq %r14, %rsp
xorl %r12d, %r12d
movq %r14, %rdi
xorl %esi, %esi
callq 0x10d0
xorl %r13d, %r13d
movl %r12d, %r15d
movq %rbx, %rdi
callq 0x1080
cmpq %r15, %rax
ja 0x2dce
jmp 0x2df4
incl %r12d
movl %r12d, %r12d
movzbl (%rbx,%r12), %ecx
cmpl $0xd, %ecx
je 0x2dcb
cmpl $0xa, %ecx
je 0x2dcb
cmpq %r12, %rax
jbe 0x2df4
movl %r13d, %eax
movb %cl, (%r14,%rax)
incl %r13d
incl %r12d
jmp 0x2db9
incl %r13d
movb $0x0, (%r14,%r13)
movq %r14, %rdi
callq 0x1080
movq %rax, %r13
movq -0x30(%rbp), %r15
movq (%r15), %rdi
movq %r14, %rsi
movq %rax, %rdx
callq 0x1160
leaq -0x58(%rbp), %rdi
movq %r15, %rsi
callq 0x30f0
movq (%r15), %r12
movq 0x18(%r15), %rax
cmpb $0x21, (%r12)
sete %dl
cmpq $0x1, %r13
sete %cl
andb %dl, %cl
testq %rax, %rax
je 0x2e56
testb %cl, %cl
je 0x2e72
movq -0x30(%rbp), %rax
movl $0xb, 0x8(%rax)
jmp 0x2f4e
testb %cl, %cl
movq -0x38(%rbp), %r14
je 0x2f16
movq -0x30(%rbp), %rax
movl $0xb, 0x8(%rax)
jmp 0x2f52
movl 0x8(%rax), %eax
decl %eax
cmpl $0x7, %eax
ja 0x2f30
leaq 0x1841(%rip), %rcx      # 0x46c8
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x30(%rbp), %r15
movl $0x5, 0x8(%r15)
movq -0x38(%rbp), %r14
movq 0x18(%r15), %r15
testq %r15, %r15
je 0x2f52
movl 0x8(%r15), %eax
orl $0x4, %eax
cmpl $0x5, %eax
jne 0x2f52
movq (%r15), %rbx
movq %r12, %rdi
movq %rbx, %rsi
callq 0x1140
testq %rbx, %rbx
je 0x2ea0
testl %eax, %eax
jne 0x2ea0
movl $0x200, %edx            # imm = 0x200
leaq -0x2a0(%rbp), %rbx
movq %rbx, %rdi
xorl %esi, %esi
callq 0x10d0
movq (%r15), %r8
movl $0x200, %esi            # imm = 0x200
movq %rbx, %rdi
leaq 0x18a9(%rip), %rdx      # 0x47a5
movq %r12, %rcx
xorl %eax, %eax
callq 0x10b0
movq -0x40(%rbp), %rdi
xorl %esi, %esi
movq %rbx, %rdx
callq 0x15d8
jmp 0x2f52
movq -0x30(%rbp), %rax
movl $0x1, 0x8(%rax)
jmp 0x2f52
movq -0x30(%rbp), %rax
movl $0x1, 0x8(%rax)
jmp 0x2f4e
cmpb $0x22, (%r14)
jne 0x2f3e
cmpb $0x22, -0x1(%r14,%r13)
jne 0x2f6d
movq -0x40(%rbp), %rdi
movq -0x30(%rbp), %rsi
movq %r14, %rdx
callq 0x2b62
movq -0x38(%rbp), %r14
xorl %edi, %edi
leaq 0x10d4(%rip), %rsi      # 0x402f
callq 0x11c0
movq %rax, %rbx
movq %r14, %rsp
xorl %eax, %eax
jmp 0x2cf0
movq %rsp, -0x80(%rbp)
movq %rbx, %rcx
movq -0x50(%rbp), %rax
subq %rax, %rcx
movq %rcx, -0x78(%rbp)
subq %rbx, %rax
movq -0x60(%rbp), %rcx
leaq (%rcx,%rax), %rdx
leaq (%rcx,%rax), %r15
addq $0xf, %r15
andq $-0x10, %r15
movq %rsp, %r12
movq %r12, -0x70(%rbp)
subq %r15, %r12
movq %r12, %rsp
movq %r12, %rdi
xorl %esi, %esi
callq 0x10d0
movq %r12, %rdi
movq %r14, %rsi
movq %r13, %rdx
callq 0x1160
movq -0x60(%rbp), %rdi
movb $0x20, (%r13,%r12)
movq -0xa0(%rbp), %rax
addq %rbx, %rax
addq %r12, %rax
movq -0x98(%rbp), %rcx
addq %rbx, %rcx
negq %r15
movq -0x70(%rbp), %rdx
addq %r15, %rdx
incq %rdx
pushq $0x1
popq %r14
addq %r14, %rbx
leaq (%rcx,%r13), %rsi
cmpq %rdi, %rsi
jae 0x3024
movb (%rbx,%r13), %sil
movb %sil, (%rdx,%r13)
incq %rax
incq %rcx
incq %rdx
incq %rbx
incq %r14
cmpb $0x22, %sil
jne 0x2ff0
movb $0x0, (%rax,%r13)
addq %r14, %r13
movq -0x40(%rbp), %rbx
jmp 0x303d
movq -0x40(%rbp), %rbx
movq %rbx, %rdi
pushq $0x1
popq %rsi
leaq 0x1758(%rip), %rdx      # 0x478d
callq 0x15d8
addq %r14, %r13
movq -0x30(%rbp), %r14
movq (%r14), %rdi
callq 0x1030
leaq 0x1(%r13), %rsi
pushq $0x1
popq %rdi
callq 0x1130
movq %rax, (%r14)
movq %rax, %rdi
movq %r12, %rsi
movq %r13, %rdx
callq 0x1160
movq %rbx, %rdi
movq %r14, %rsi
movq %r12, %rdx
callq 0x2b62
movq -0x78(%rbp), %rbx
addq -0x50(%rbp), %rbx
movq %r12, %rdi
callq 0x1080
addq %rax, %rbx
movq %rbx, %rdi
leaq 0xf9e(%rip), %rsi       # 0x402f
callq 0x11c0
movq %rax, %rbx
movq -0x80(%rbp), %rsp
movq -0x38(%rbp), %r14
jmp 0x2f63
movq -0x50(%rbp), %rdi
callq 0x1030
movl $0x2401, %ecx           # imm = 0x2401
movq -0x68(%rbp), %rdx
jmp 0x2c61
pushq $0x1
popq %rdi
pushq $0x20
popq %rsi
callq 0x1130
movl $0x9, 0x8(%rax)
leaq -0x58(%rbp), %rbx
movq %rbx, %rdi
movq %rax, %rsi
callq 0x30f0
movq (%rbx), %rax
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq