Merge pull request #3 from mc-lang/functions

Functions
This commit is contained in:
MCorange99 2023-04-13 00:54:38 +03:00 committed by GitHub
commit c40934c052
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1763 additions and 961 deletions

Binary file not shown.

Binary file not shown.

View File

@ -2,7 +2,7 @@
"name": "mclang", "name": "mclang",
"displayName": "mclang", "displayName": "mclang",
"description": "Code highlighting for mclang", "description": "Code highlighting for mclang",
"version": "0.0.1", "version": "0.0.2",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git@github.com:mc-lang/mclang2.git" "url": "git@github.com:mc-lang/mclang2.git"
@ -37,6 +37,6 @@
}, },
"dependencies": { "dependencies": {
"generator-code": "^1.7.4", "generator-code": "^1.7.4",
"vsce": "^2.15.0" "@vscode/vsce": "^2.15.0"
} }
} }

File diff suppressed because one or more lines are too long

1
include/compat.mcl Normal file
View File

@ -0,0 +1 @@
// todo: add some sort of macrow

View File

@ -1,19 +1,18 @@
const FS_O_APPEND 1024 end // append to existing file
macro FS_O_APPEND 1024 end // append to existing file const FS_O_ASYNC 8192 end // use signal-driven IO
macro FS_O_ASYNC 8192 end // use signal-driven IO const FS_O_CLOEXEC 524288 end // use close-on-exec (avoid race conditions and lock contentions)
macro FS_O_CLOEXEC 524288 end // use close-on-exec (avoid race conditions and lock contentions) const FS_O_CREAT 64 end // create file if it doesnt exist
macro FS_O_CREAT 64 end // create file if it doesnt exist const FS_O_DIRECT 16384 end // bypass cache (slower)
macro FS_O_DIRECT 16384 end // bypass cache (slower) const FS_O_DIRECTORY 65536 end // fail if pathname isnt a directory
macro FS_O_DIRECTORY 65536 end // fail if pathname isnt a directory const FS_O_DSYNC 4096 end // ensure output is sent to hardware and metadata written before return
macro FS_O_DSYNC 4096 end // ensure output is sent to hardware and metadata written before return const FS_O_EXCL 128 end // ensure creation of file
macro FS_O_EXCL 128 end // ensure creation of file const FS_O_LARGEFILE 0 end // allows use of file sizes represented by off64_t
macro FS_O_LARGEFILE 0 end // allows use of file sizes represented by off64_t const FS_O_NOATIME 262144 end // do not increment access time upon open
macro FS_O_NOATIME 262144 end // do not increment access time upon open const FS_O_NOCTTY 256 end // if pathname is a terminal device, dont become controlling terminal
macro FS_O_NOCTTY 256 end // if pathname is a terminal device, dont become controlling terminal const FS_O_NOFOLLOW 131072 end // fail if pathname is symbolic link
macro FS_O_NOFOLLOW 131072 end // fail if pathname is symbolic link const FS_O_NONBLOCK 2048 end // if possible, open file with non-blocking IO
macro FS_O_NONBLOCK 2048 end // if possible, open file with non-blocking IO const FS_O_NDELAY 2048 end // same as O_NONBLOCK
macro FS_O_NDELAY 2048 end // same as O_NONBLOCK const FS_O_PATH 2097152 end // open descriptor for obtaining permissions and status of a file but does not allow read/write operations
macro FS_O_PATH 2097152 end // open descriptor for obtaining permissions and status of a file but does not allow read/write operations const FS_O_SYNC 1052672 end // wait for IO to complete before returning
macro FS_O_SYNC 1052672 end // wait for IO to complete before returning const FS_O_TMPFILE 4259840 end // create an unnamed, unreachable (via any other open call) temporary file
macro FS_O_TMPFILE 4259840 end // create an unnamed, unreachable (via any other open call) temporary file const FS_O_TRUNC 512 end // if file exists, ovewrite it (careful!)
macro FS_O_TRUNC 512 end // if file exists, ovewrite it (careful!)

View File

@ -1,16 +1,15 @@
macro NULL 0 end const NULL 0 end
macro false 0 end const false 0 end
macro true 1 end const true 1 end
macro div divmod drop end fn div with int int returns int then divmod drop done
macro mod divmod swap drop end fn mod with int int returns int then divmod swap drop done
macro / div end
macro % mod end
macro 2dup over over end
macro 2drop drop drop end
macro sizeof(u64) 8 end fn dup2 with any any returns any any any any then over over done
macro sizeof(u32) 4 end fn drop2 with any any returns void then drop drop done
macro sizeof(u16) 2 end
macro sizeof(u8) 1 end const sizeof(u64) 8 end
const sizeof(u32) 4 end
const sizeof(u16) 2 end
const sizeof(u8) 1 end

View File

@ -5,9 +5,9 @@
// @arg buff_ptr: Ptr - pointer to the buffer to write // @arg buff_ptr: Ptr - pointer to the buffer to write
// @arg fd: Int - file descriptor // @arg fd: Int - file descriptor
// @ret Int // @ret Int
macro write fn write with int ptr int returns int then
SYS_write syscall3 SYS_write syscall3
end done
// Write to a file descriptor using the SYS_write syscall // Write to a file descriptor using the SYS_write syscall
// args: [buff_size, buff_ptr, fd] // args: [buff_size, buff_ptr, fd]
@ -15,9 +15,9 @@ end
// @arg buff_ptr: Ptr - pointer to the buffer to write // @arg buff_ptr: Ptr - pointer to the buffer to write
// @arg fd: Int - file descriptor // @arg fd: Int - file descriptor
// @ret Int // @ret Int
macro read fn read with int ptr int returns int then
SYS_read syscall3 SYS_read syscall3
end done
// Print a string to STDOUT // Print a string to STDOUT
@ -25,18 +25,18 @@ end
// @arg buff_size: Int - number of bytes to write // @arg buff_size: Int - number of bytes to write
// @arg buff_ptr: Ptr - pointer to the buffer to write // @arg buff_ptr: Ptr - pointer to the buffer to write
// @ret NULL // @ret NULL
macro puts fn puts with int ptr returns void then
STDOUT write drop STDOUT write drop
end done
// Print a string to STDERR // Print a string to STDERR
// args: [str_size, str_ptr] // args: [str_size, str_ptr]
// @arg buff_size: Int - number of bytes to write // @arg buff_size: Int - number of bytes to write
// @arg buff_ptr: Ptr - pointer to the buffer to write // @arg buff_ptr: Ptr - pointer to the buffer to write
// @ret NULL // @ret NULL
macro eputs fn eputs with int ptr returns void then
STDOUT write drop STDOUT write drop
end done
// TODO: make putc and eputc after we make local mem // TODO: make putc and eputc after we make local mem
@ -44,7 +44,7 @@ end
// args: [exit_code] // args: [exit_code]
// @arg exit_code: Int // @arg exit_code: Int
// @ret NULL/NEVER // @ret NULL/NEVER
macro exit fn exit with int returns void then
SYS_exit syscall1 drop SYS_exit syscall1 drop
end done

View File

@ -1,322 +1,322 @@
// file descriptors // file descriptors
macro STDIN 0 end const STDIN 0 end
macro STDOUT 1 end const STDOUT 1 end
macro STDERR 2 end const STDERR 2 end
// syscalls // syscalls
macro SYS_read 0 end const SYS_read 0 end
macro SYS_write 1 end const SYS_write 1 end
macro SYS_open 2 end const SYS_open 2 end
macro SYS_close 3 end const SYS_close 3 end
macro SYS_stat 4 end const SYS_stat 4 end
macro SYS_fstat 5 end const SYS_fstat 5 end
macro SYS_lstat 6 end const SYS_lstat 6 end
macro SYS_poll 7 end const SYS_poll 7 end
macro SYS_lseek 8 end const SYS_lseek 8 end
macro SYS_mmap 9 end const SYS_mmap 9 end
macro SYS_mprotect 10 end const SYS_mprotect 10 end
macro SYS_munmap 11 end const SYS_munmap 11 end
macro SYS_brk 12 end const SYS_brk 12 end
macro SYS_rt_sigaction 13 end const SYS_rt_sigaction 13 end
macro SYS_rt_sigprocmask 14 end const SYS_rt_sigprocmask 14 end
macro SYS_rt_sigreturn 15 end const SYS_rt_sigreturn 15 end
macro SYS_ioctl 16 end const SYS_ioctl 16 end
macro SYS_pread64 17 end const SYS_pread64 17 end
macro SYS_pwrite64 18 end const SYS_pwrite64 18 end
macro SYS_readv 19 end const SYS_readv 19 end
macro SYS_writev 20 end const SYS_writev 20 end
macro SYS_access 21 end const SYS_access 21 end
macro SYS_pipe 22 end const SYS_pipe 22 end
macro SYS_select 23 end const SYS_select 23 end
macro SYS_sched_yield 24 end const SYS_sched_yield 24 end
macro SYS_mremap 25 end const SYS_mremap 25 end
macro SYS_msync 26 end const SYS_msync 26 end
macro SYS_mincore 27 end const SYS_mincore 27 end
macro SYS_madvise 28 end const SYS_madvise 28 end
macro SYS_shmget 29 end const SYS_shmget 29 end
macro SYS_shmat 30 end const SYS_shmat 30 end
macro SYS_shmctl 31 end const SYS_shmctl 31 end
macro SYS_dup 32 end const SYS_dup 32 end
macro SYS_dup2 33 end const SYS_dup2 33 end
macro SYS_pause 34 end const SYS_pause 34 end
macro SYS_nanosleep 35 end const SYS_nanosleep 35 end
macro SYS_getitimer 36 end const SYS_getitimer 36 end
macro SYS_alarm 37 end const SYS_alarm 37 end
macro SYS_setitimer 38 end const SYS_setitimer 38 end
macro SYS_getpid 39 end const SYS_getpid 39 end
macro SYS_sendfile 40 end const SYS_sendfile 40 end
macro SYS_socket 41 end const SYS_socket 41 end
macro SYS_connect 42 end const SYS_connect 42 end
macro SYS_accept 43 end const SYS_accept 43 end
macro SYS_sendto 44 end const SYS_sendto 44 end
macro SYS_recvfrom 45 end const SYS_recvfrom 45 end
macro SYS_sendmsg 46 end const SYS_sendmsg 46 end
macro SYS_recvmsg 47 end const SYS_recvmsg 47 end
macro SYS_shutdown 48 end const SYS_shutdown 48 end
macro SYS_bind 49 end const SYS_bind 49 end
macro SYS_listen 50 end const SYS_listen 50 end
macro SYS_getsockname 51 end const SYS_getsockname 51 end
macro SYS_getpeername 52 end const SYS_getpeername 52 end
macro SYS_socketpair 53 end const SYS_socketpair 53 end
macro SYS_setsockopt 54 end const SYS_setsockopt 54 end
macro SYS_getsockopt 55 end const SYS_getsockopt 55 end
macro SYS_clone 56 end const SYS_clone 56 end
macro SYS_fork 57 end const SYS_fork 57 end
macro SYS_vfork 58 end const SYS_vfork 58 end
macro SYS_execve 59 end const SYS_execve 59 end
macro SYS_exit 60 end const SYS_exit 60 end
macro SYS_wait4 61 end const SYS_wait4 61 end
macro SYS_kill 62 end const SYS_kill 62 end
macro SYS_uname 63 end const SYS_uname 63 end
macro SYS_semget 64 end const SYS_semget 64 end
macro SYS_semop 65 end const SYS_semop 65 end
macro SYS_semctl 66 end const SYS_semctl 66 end
macro SYS_shmdt 67 end const SYS_shmdt 67 end
macro SYS_msgget 68 end const SYS_msgget 68 end
macro SYS_msgsnd 69 end const SYS_msgsnd 69 end
macro SYS_msgrcv 70 end const SYS_msgrcv 70 end
macro SYS_msgctl 71 end const SYS_msgctl 71 end
macro SYS_fcntl 72 end const SYS_fcntl 72 end
macro SYS_flock 73 end const SYS_flock 73 end
macro SYS_fsync 74 end const SYS_fsync 74 end
macro SYS_fdatasync 75 end const SYS_fdatasync 75 end
macro SYS_truncate 76 end const SYS_truncate 76 end
macro SYS_ftruncate 77 end const SYS_ftruncate 77 end
macro SYS_getdents 78 end const SYS_getdents 78 end
macro SYS_getcwd 79 end const SYS_getcwd 79 end
macro SYS_chdir 80 end const SYS_chdir 80 end
macro SYS_fchdir 81 end const SYS_fchdir 81 end
macro SYS_rename 82 end const SYS_rename 82 end
macro SYS_mkdir 83 end const SYS_mkdir 83 end
macro SYS_rmdir 84 end const SYS_rmdir 84 end
macro SYS_creat 85 end const SYS_creat 85 end
macro SYS_link 86 end const SYS_link 86 end
macro SYS_unlink 87 end const SYS_unlink 87 end
macro SYS_symlink 88 end const SYS_symlink 88 end
macro SYS_readlink 89 end const SYS_readlink 89 end
macro SYS_chmod 90 end const SYS_chmod 90 end
macro SYS_fchmod 91 end const SYS_fchmod 91 end
macro SYS_chown 92 end const SYS_chown 92 end
macro SYS_fchown 93 end const SYS_fchown 93 end
macro SYS_lchown 94 end const SYS_lchown 94 end
macro SYS_umask 95 end const SYS_umask 95 end
macro SYS_gettimeofday 96 end const SYS_gettimeofday 96 end
macro SYS_getrlimit 97 end const SYS_getrlimit 97 end
macro SYS_getrusage 98 end const SYS_getrusage 98 end
macro SYS_sysinfo 99 end const SYS_sysinfo 99 end
macro SYS_times 100 end const SYS_times 100 end
macro SYS_ptrace 101 end const SYS_ptrace 101 end
macro SYS_getuid 102 end const SYS_getuid 102 end
macro SYS_syslog 103 end const SYS_syslog 103 end
macro SYS_getgid 104 end const SYS_getgid 104 end
macro SYS_setuid 105 end const SYS_setuid 105 end
macro SYS_setgid 106 end const SYS_setgid 106 end
macro SYS_geteuid 107 end const SYS_geteuid 107 end
macro SYS_getegid 108 end const SYS_getegid 108 end
macro SYS_setpgid 109 end const SYS_setpgid 109 end
macro SYS_getppid 110 end const SYS_getppid 110 end
macro SYS_getpgrp 111 end const SYS_getpgrp 111 end
macro SYS_setsid 112 end const SYS_setsid 112 end
macro SYS_setreuid 113 end const SYS_setreuid 113 end
macro SYS_setregid 114 end const SYS_setregid 114 end
macro SYS_getgroups 115 end const SYS_getgroups 115 end
macro SYS_setgroups 116 end const SYS_setgroups 116 end
macro SYS_setresuid 117 end const SYS_setresuid 117 end
macro SYS_getresuid 118 end const SYS_getresuid 118 end
macro SYS_setresgid 119 end const SYS_setresgid 119 end
macro SYS_getresgid 120 end const SYS_getresgid 120 end
macro SYS_getpgid 121 end const SYS_getpgid 121 end
macro SYS_setfsuid 122 end const SYS_setfsuid 122 end
macro SYS_setfsgid 123 end const SYS_setfsgid 123 end
macro SYS_getsid 124 end const SYS_getsid 124 end
macro SYS_capget 125 end const SYS_capget 125 end
macro SYS_capset 126 end const SYS_capset 126 end
macro SYS_rt_sigpending 127 end const SYS_rt_sigpending 127 end
macro SYS_rt_sigtimedwait 128 end const SYS_rt_sigtimedwait 128 end
macro SYS_rt_sigqueueinfo 129 end const SYS_rt_sigqueueinfo 129 end
macro SYS_rt_sigsuspend 130 end const SYS_rt_sigsuspend 130 end
macro SYS_sigaltstack 131 end const SYS_sigaltstack 131 end
macro SYS_utime 132 end const SYS_utime 132 end
macro SYS_mknod 133 end const SYS_mknod 133 end
macro SYS_uselib 134 end const SYS_uselib 134 end
macro SYS_personality 135 end const SYS_personality 135 end
macro SYS_ustat 136 end const SYS_ustat 136 end
macro SYS_statfs 137 end const SYS_statfs 137 end
macro SYS_fstatfs 138 end const SYS_fstatfs 138 end
macro SYS_sysfs 139 end const SYS_sysfs 139 end
macro SYS_getpriority 140 end const SYS_getpriority 140 end
macro SYS_setpriority 141 end const SYS_setpriority 141 end
macro SYS_sched_setparam 142 end const SYS_sched_setparam 142 end
macro SYS_sched_getparam 143 end const SYS_sched_getparam 143 end
macro SYS_sched_setscheduler 144 end const SYS_sched_setscheduler 144 end
macro SYS_sched_getscheduler 145 end const SYS_sched_getscheduler 145 end
macro SYS_sched_get_priority_max 146 end const SYS_sched_get_priority_max 146 end
macro SYS_sched_get_priority_min 147 end const SYS_sched_get_priority_min 147 end
macro SYS_sched_rr_get_interval 148 end const SYS_sched_rr_get_interval 148 end
macro SYS_mlock 149 end const SYS_mlock 149 end
macro SYS_munlock 150 end const SYS_munlock 150 end
macro SYS_mlockall 151 end const SYS_mlockall 151 end
macro SYS_munlockall 152 end const SYS_munlockall 152 end
macro SYS_vhangup 153 end const SYS_vhangup 153 end
macro SYS_modify_ldt 154 end const SYS_modify_ldt 154 end
macro SYS_pivot_root 155 end const SYS_pivot_root 155 end
macro SYS__sysctl 156 end const SYS__sysctl 156 end
macro SYS_prctl 157 end const SYS_prctl 157 end
macro SYS_arch_prctl 158 end const SYS_arch_prctl 158 end
macro SYS_adjtimex 159 end const SYS_adjtimex 159 end
macro SYS_setrlimit 160 end const SYS_setrlimit 160 end
macro SYS_chroot 161 end const SYS_chroot 161 end
macro SYS_sync 162 end const SYS_sync 162 end
macro SYS_acct 163 end const SYS_acct 163 end
macro SYS_settimeofday 164 end const SYS_settimeofday 164 end
macro SYS_mount 165 end const SYS_mount 165 end
macro SYS_umount2 166 end const SYS_umount2 166 end
macro SYS_swapon 167 end const SYS_swapon 167 end
macro SYS_swapoff 168 end const SYS_swapoff 168 end
macro SYS_reboot 169 end const SYS_reboot 169 end
macro SYS_sethostname 170 end const SYS_sethostname 170 end
macro SYS_setdomainname 171 end const SYS_setdomainname 171 end
macro SYS_iopl 172 end const SYS_iopl 172 end
macro SYS_ioperm 173 end const SYS_ioperm 173 end
macro SYS_create_module 174 end const SYS_create_module 174 end
macro SYS_init_module 175 end const SYS_init_module 175 end
macro SYS_delete_module 176 end const SYS_delete_module 176 end
macro SYS_get_kernel_syms 177 end const SYS_get_kernel_syms 177 end
macro SYS_query_module 178 end const SYS_query_module 178 end
macro SYS_quotactl 179 end const SYS_quotactl 179 end
macro SYS_nfsservctl 180 end const SYS_nfsservctl 180 end
macro SYS_getpmsg 181 end const SYS_getpmsg 181 end
macro SYS_putpmsg 182 end const SYS_putpmsg 182 end
macro SYS_afs_syscall 183 end const SYS_afs_syscall 183 end
macro SYS_tuxcall 184 end const SYS_tuxcall 184 end
macro SYS_security 185 end const SYS_security 185 end
macro SYS_gettid 186 end const SYS_gettid 186 end
macro SYS_readahead 187 end const SYS_readahead 187 end
macro SYS_setxattr 188 end const SYS_setxattr 188 end
macro SYS_lsetxattr 189 end const SYS_lsetxattr 189 end
macro SYS_fsetxattr 190 end const SYS_fsetxattr 190 end
macro SYS_getxattr 191 end const SYS_getxattr 191 end
macro SYS_lgetxattr 192 end const SYS_lgetxattr 192 end
macro SYS_fgetxattr 193 end const SYS_fgetxattr 193 end
macro SYS_listxattr 194 end const SYS_listxattr 194 end
macro SYS_llistxattr 195 end const SYS_llistxattr 195 end
macro SYS_flistxattr 196 end const SYS_flistxattr 196 end
macro SYS_removexattr 197 end const SYS_removexattr 197 end
macro SYS_lremovexattr 198 end const SYS_lremovexattr 198 end
macro SYS_fremovexattr 199 end const SYS_fremovexattr 199 end
macro SYS_tkill 200 end const SYS_tkill 200 end
macro SYS_time 201 end const SYS_time 201 end
macro SYS_futex 202 end const SYS_futex 202 end
macro SYS_sched_setaffinity 203 end const SYS_sched_setaffinity 203 end
macro SYS_sched_getaffinity 204 end const SYS_sched_getaffinity 204 end
macro SYS_set_thread_area 205 end const SYS_set_thread_area 205 end
macro SYS_io_setup 206 end const SYS_io_setup 206 end
macro SYS_io_destroy 207 end const SYS_io_destroy 207 end
macro SYS_io_getevents 208 end const SYS_io_getevents 208 end
macro SYS_io_submit 209 end const SYS_io_submit 209 end
macro SYS_io_cancel 210 end const SYS_io_cancel 210 end
macro SYS_get_thread_area 211 end const SYS_get_thread_area 211 end
macro SYS_lookup_dcookie 212 end const SYS_lookup_dcookie 212 end
macro SYS_epoll_create 213 end const SYS_epoll_create 213 end
macro SYS_epoll_ctl_old 214 end const SYS_epoll_ctl_old 214 end
macro SYS_epoll_wait_old 215 end const SYS_epoll_wait_old 215 end
macro SYS_remap_file_pages 216 end const SYS_remap_file_pages 216 end
macro SYS_getdents64 217 end const SYS_getdents64 217 end
macro SYS_set_tid_address 218 end const SYS_set_tid_address 218 end
macro SYS_restart_syscall 219 end const SYS_restart_syscall 219 end
macro SYS_semtimedop 220 end const SYS_semtimedop 220 end
macro SYS_fadvise64 221 end const SYS_fadvise64 221 end
macro SYS_timer_create 222 end const SYS_timer_create 222 end
macro SYS_timer_settime 223 end const SYS_timer_settime 223 end
macro SYS_timer_gettime 224 end const SYS_timer_gettime 224 end
macro SYS_timer_getoverrun 225 end const SYS_timer_getoverrun 225 end
macro SYS_timer_delete 226 end const SYS_timer_delete 226 end
macro SYS_clock_settime 227 end const SYS_clock_settime 227 end
macro SYS_clock_gettime 228 end const SYS_clock_gettime 228 end
macro SYS_clock_getres 229 end const SYS_clock_getres 229 end
macro SYS_clock_nanosleep 230 end const SYS_clock_nanosleep 230 end
macro SYS_exit_group 231 end const SYS_exit_group 231 end
macro SYS_epoll_wait 232 end const SYS_epoll_wait 232 end
macro SYS_epoll_ctl 233 end const SYS_epoll_ctl 233 end
macro SYS_tgkill 234 end const SYS_tgkill 234 end
macro SYS_utimes 235 end const SYS_utimes 235 end
macro SYS_vserver 236 end const SYS_vserver 236 end
macro SYS_mbind 237 end const SYS_mbind 237 end
macro SYS_set_mempolicy 238 end const SYS_set_mempolicy 238 end
macro SYS_get_mempolicy 239 end const SYS_get_mempolicy 239 end
macro SYS_mq_open 240 end const SYS_mq_open 240 end
macro SYS_mq_unlink 241 end const SYS_mq_unlink 241 end
macro SYS_mq_timedsend 242 end const SYS_mq_timedsend 242 end
macro SYS_mq_timedreceive 243 end const SYS_mq_timedreceive 243 end
macro SYS_mq_notify 244 end const SYS_mq_notify 244 end
macro SYS_mq_getsetattr 245 end const SYS_mq_getsetattr 245 end
macro SYS_kexec_load 246 end const SYS_kexec_load 246 end
macro SYS_waitid 247 end const SYS_waitid 247 end
macro SYS_add_key 248 end const SYS_add_key 248 end
macro SYS_request_key 249 end const SYS_request_key 249 end
macro SYS_keyctl 250 end const SYS_keyctl 250 end
macro SYS_ioprio_set 251 end const SYS_ioprio_set 251 end
macro SYS_ioprio_get 252 end const SYS_ioprio_get 252 end
macro SYS_inotify_init 253 end const SYS_inotify_init 253 end
macro SYS_inotify_add_watch 254 end const SYS_inotify_add_watch 254 end
macro SYS_inotify_rm_watch 255 end const SYS_inotify_rm_watch 255 end
macro SYS_migrate_pages 256 end const SYS_migrate_pages 256 end
macro SYS_openat 257 end const SYS_openat 257 end
macro SYS_mkdirat 258 end const SYS_mkdirat 258 end
macro SYS_mknodat 259 end const SYS_mknodat 259 end
macro SYS_fchownat 260 end const SYS_fchownat 260 end
macro SYS_futimesat 261 end const SYS_futimesat 261 end
macro SYS_newfstatat 262 end const SYS_newfstatat 262 end
macro SYS_unlinkat 263 end const SYS_unlinkat 263 end
macro SYS_renameat 264 end const SYS_renameat 264 end
macro SYS_linkat 265 end const SYS_linkat 265 end
macro SYS_symlinkat 266 end const SYS_symlinkat 266 end
macro SYS_readlinkat 267 end const SYS_readlinkat 267 end
macro SYS_fchmodat 268 end const SYS_fchmodat 268 end
macro SYS_faccessat 269 end const SYS_faccessat 269 end
macro SYS_pselect6 270 end const SYS_pselect6 270 end
macro SYS_ppoll 271 end const SYS_ppoll 271 end
macro SYS_unshare 272 end const SYS_unshare 272 end
macro SYS_set_robust_list 273 end const SYS_set_robust_list 273 end
macro SYS_get_robust_list 274 end const SYS_get_robust_list 274 end
macro SYS_splice 275 end const SYS_splice 275 end
macro SYS_tee 276 end const SYS_tee 276 end
macro SYS_sync_file_range 277 end const SYS_sync_file_range 277 end
macro SYS_vmsplice 278 end const SYS_vmsplice 278 end
macro SYS_move_pages 279 end const SYS_move_pages 279 end
macro SYS_utimensat 280 end const SYS_utimensat 280 end
macro SYS_epoll_pwait 281 end const SYS_epoll_pwait 281 end
macro SYS_signalfd 282 end const SYS_signalfd 282 end
macro SYS_timerfd_create 283 end const SYS_timerfd_create 283 end
macro SYS_eventfd 284 end const SYS_eventfd 284 end
macro SYS_fallocate 285 end const SYS_fallocate 285 end
macro SYS_timerfd_settime 286 end const SYS_timerfd_settime 286 end
macro SYS_timerfd_gettime 287 end const SYS_timerfd_gettime 287 end
macro SYS_accept4 288 end const SYS_accept4 288 end
macro SYS_signalfd4 289 end const SYS_signalfd4 289 end
macro SYS_eventfd2 290 end const SYS_eventfd2 290 end
macro SYS_epoll_create1 291 end const SYS_epoll_create1 291 end
macro SYS_dup3 292 end const SYS_dup3 292 end
macro SYS_pipe2 293 end const SYS_pipe2 293 end
macro SYS_inotify_init1 294 end const SYS_inotify_init1 294 end
macro SYS_preadv 295 end const SYS_preadv 295 end
macro SYS_pwritev 296 end const SYS_pwritev 296 end
macro SYS_rt_tgsigqueueinfo 297 end const SYS_rt_tgsigqueueinfo 297 end
macro SYS_perf_event_open 298 end const SYS_perf_event_open 298 end
macro SYS_recvmmsg 299 end const SYS_recvmmsg 299 end
macro SYS_fanotify_init 300 end const SYS_fanotify_init 300 end
macro SYS_fanotify_mark 301 end const SYS_fanotify_mark 301 end
macro SYS_prlimit64 302 end const SYS_prlimit64 302 end
macro SYS_name_to_handle_at 303 end const SYS_name_to_handle_at 303 end
macro SYS_open_by_handle_at 304 end const SYS_open_by_handle_at 304 end
macro SYS_clock_adjtime 305 end const SYS_clock_adjtime 305 end
macro SYS_syncfs 306 end const SYS_syncfs 306 end
macro SYS_sendmmsg 307 end const SYS_sendmmsg 307 end
macro SYS_setns 308 end const SYS_setns 308 end
macro SYS_getcpu 309 end const SYS_getcpu 309 end
macro SYS_process_vm_readv 310 end const SYS_process_vm_readv 310 end
macro SYS_process_vm_writev 311 end const SYS_process_vm_writev 311 end
macro SYS_kcmp 312 end const SYS_kcmp 312 end
macro SYS_finit_module 313 end const SYS_finit_module 313 end

View File

@ -1,27 +0,0 @@
macro load8 @8 end
macro store8 !8 end
macro load64
7 + 0
8 shl over !8 + swap 1 - swap
8 shl over !8 + swap 1 - swap
8 shl over !8 + swap 1 - swap
8 shl over !8 + swap 1 - swap
8 shl over !8 + swap 1 - swap
8 shl over !8 + swap 1 - swap
8 shl over !8 + swap 1 - swap
8 shl over !8 + swap drop
end
macro store64
2dup 255 band @8 shr swap 1 + swap
2dup 255 band @8 shr swap 1 + swap
2dup 255 band @8 shr swap 1 + swap
2dup 255 band @8 shr swap 1 + swap
2dup 255 band @8 shr swap 1 + swap
2dup 255 band @8 shr swap 1 + swap
2dup 255 band @8 shr swap 1 + swap
2dup 255 band @8 shr swap 2drop
end

View File

@ -2,4 +2,5 @@ include "linux.mcl"
include "io.mcl" include "io.mcl"
include "util.mcl" include "util.mcl"
include "int.mcl" include "int.mcl"
include "fs.mcl" include "fs.mcl"
include "compat.mcl"

View File

@ -5,11 +5,11 @@
// @arg str_len: Int // @arg str_len: Int
// @arg str_ptr: Ptr // @arg str_ptr: Ptr
// @ret NULL/NEVER // @ret NULL/NEVER
macro assert fn assert with bool int ptr returns void then
rot rot
if else if else
"Assert failed: \"" eputs eputs "Assert failed: \"" eputs eputs
"\". Exiting!\n" eputs "\". Exiting!\n" eputs
1 exit 1 exit
end end
end done

View File

@ -1,12 +1,15 @@
use std::{fs, path::PathBuf, io::{Write, BufWriter}}; use std::{fs, path::PathBuf, io::{Write, BufWriter}, collections::HashMap};
use crate::{constants::{Operator, OpType, KeywordType}, Args}; use crate::{constants::{Operator, OpType, KeywordType}, Args};
use color_eyre::Result; use color_eyre::Result;
use crate::compile::commands::linux_x86_64_compile_and_link; use crate::compile::commands::linux_x86_64_compile_and_link;
use crate::constants::InstructionType; use crate::constants::InstructionType;
use super::commands::linux_x86_64_run; use super::{commands::linux_x86_64_run, Constant, Memory, Function};
use eyre::eyre;
pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
let debug = args.get_opt_level()? < 1;
let mut of_c = PathBuf::from(&args.out_file); let mut of_c = PathBuf::from(&args.out_file);
let (mut of_o, mut of_a) = if args.out_file == *crate::DEFAULT_OUT_FILE { let (mut of_o, mut of_a) = if args.out_file == *crate::DEFAULT_OUT_FILE {
let of_o = PathBuf::from("/tmp/mclang_comp.o"); let of_o = PathBuf::from("/tmp/mclang_comp.o");
@ -22,18 +25,19 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
of_o.set_extension("o"); of_o.set_extension("o");
of_a.set_extension("nasm"); of_a.set_extension("nasm");
let file = fs::File::create(&of_a)?; let file = fs::File::create(&of_a)?;
let mut writer = BufWriter::new(&file); let mut writer = BufWriter::new(&file);
let mut memories: Vec<(usize, usize)> = Vec::new(); let mut memories: Vec<Memory> = Vec::new();
let mut constants: HashMap<String, Constant> = HashMap::new();
let mut functions: Vec<Function> = Vec::new();
// println!("{}", tokens.len()); // println!("{}", tokens.len());
let mut strings: Vec<String> = Vec::new(); let mut strings: Vec<String> = Vec::new();
writeln!(writer, "BITS 64")?; writeln!(writer, "BITS 64")?;
writeln!(writer, "segment .text")?; writeln!(writer, "segment .text")?;
writeln!(writer, "print:")?; writeln!(writer, "_dbg_print:")?;
writeln!(writer, " mov r9, -3689348814741910323")?; writeln!(writer, " mov r9, -3689348814741910323")?;
writeln!(writer, " sub rsp, 40")?; writeln!(writer, " sub rsp, 40")?;
writeln!(writer, " mov BYTE [rsp+31], 10")?; writeln!(writer, " mov BYTE [rsp+31], 10")?;
@ -68,46 +72,76 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
writeln!(writer, " ret")?; writeln!(writer, " ret")?;
writeln!(writer, "global _start")?; writeln!(writer, "global _start")?;
writeln!(writer, "_start:")?; writeln!(writer, "_start:")?;
writeln!(writer, " lea rbp, [rel ret_stack]")?;
writeln!(writer, " call main")?;
writeln!(writer, " jmp end")?;
let mut ti = 0; let mut ti = 0;
while ti < tokens.len() { while ti < tokens.len() {
let token = &tokens[ti]; let token = &tokens[ti];
// println!("{:?}", token);
if debug {
writeln!(writer, "addr_{ti}:")?;
if token.typ == OpType::Instruction(InstructionType::PushInt) {
writeln!(writer, " ;; -- {:?} {}", token.typ, token.value)?;
} else if token.typ == OpType::Instruction(InstructionType::PushStr) {
writeln!(writer, " ;; -- {:?} {}", token.typ, token.text.escape_debug())?;
} else {
writeln!(writer, " ;; -- {:?}", token.typ)?;
}
} else {
writeln!(writer, "addr_{ti}:")?; if ti != 0 && tokens[ti-1].typ == OpType::Keyword(KeywordType::Else) ||
tokens[ti-1].typ == OpType::Keyword(KeywordType::End){
writeln!(writer, "addr_{ti}:")?;
}
if ti + 1 < tokens.len() && tokens[ti+1].typ == OpType::Keyword(KeywordType::End) {
writeln!(writer, "addr_{ti}:")?;
}
if let OpType::Keyword(keyword) = &token.typ {
match keyword {
&KeywordType::End |
&KeywordType::While => {
writeln!(writer, "addr_{ti}:")?;
}
_ => ()
}
}
}
match token.typ.clone() { match token.typ.clone() {
// stack // stack
OpType::Instruction(instruction) => { OpType::Instruction(instruction) => {
match instruction { match instruction {
InstructionType::PushInt => { InstructionType::PushInt => {
writeln!(writer, " ;; -- push int {}", token.value)?;
writeln!(writer, " mov rax, {}", token.value)?; writeln!(writer, " mov rax, {}", token.value)?;
writeln!(writer, " push rax")?; writeln!(writer, " push rax")?;
ti += 1; ti += 1;
}, },
InstructionType::PushStr => { InstructionType::PushStr => {
writeln!(writer, " ;; -- push str \"{}\"", token.text.escape_default())?;
writeln!(writer, " mov rax, {}", token.text.len())?; writeln!(writer, " mov rax, {}", token.text.len())?;
writeln!(writer, " push rax")?; writeln!(writer, " push rax")?;
writeln!(writer, " push str_{}", strings.len())?; writeln!(writer, " mov rax, str_{}", strings.len())?;
writeln!(writer, " push rax")?;
strings.push(token.text.clone()); strings.push(token.text.clone());
ti += 1; ti += 1;
} }
InstructionType::Drop => { InstructionType::Drop => {
writeln!(writer, " ;; -- drop")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
ti += 1; ti += 1;
}, },
InstructionType::Print => { InstructionType::Print => {
writeln!(writer, " ;; -- print")?;
writeln!(writer, " pop rdi")?; writeln!(writer, " pop rdi")?;
writeln!(writer, " call print")?; writeln!(writer, " call _dbg_print")?;
ti += 1; ti += 1;
}, },
InstructionType::Dup => { InstructionType::Dup => {
writeln!(writer, " ;; -- dup")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " push rax")?; writeln!(writer, " push rax")?;
writeln!(writer, " push rax")?; writeln!(writer, " push rax")?;
@ -116,7 +150,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
}, },
InstructionType::Rot => { InstructionType::Rot => {
writeln!(writer, " ;; -- rot")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
writeln!(writer, " pop rcx")?; writeln!(writer, " pop rcx")?;
@ -127,7 +160,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Swap => { InstructionType::Swap => {
writeln!(writer, " ;; -- swap")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
writeln!(writer, " push rax")?; writeln!(writer, " push rax")?;
@ -136,7 +168,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Over => { InstructionType::Over => {
writeln!(writer, " ;; -- over")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
writeln!(writer, " push rbx")?; writeln!(writer, " push rbx")?;
@ -145,33 +176,51 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
//mem
InstructionType::Mem => {
writeln!(writer, " ;; -- mem")?;
writeln!(writer, " push mem")?;
ti += 1;
}
InstructionType::Load8 => { InstructionType::Load8 => {
writeln!(writer, " ;; -- load")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " xor rbx, rbx")?; writeln!(writer, " xor rbx, rbx")?;
writeln!(writer, " mov bl, [rax]")?; writeln!(writer, " mov bl, byte [rax]")?;
writeln!(writer, " push rbx")?; writeln!(writer, " push rbx")?;
ti += 1; ti += 1;
} }
InstructionType::Store8 => { InstructionType::Store8 => {
writeln!(writer, " ;; -- store")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " mov [rax], bl")?; writeln!(writer, " mov byte [rax], bl")?;
ti += 1;
}
InstructionType::Load32 => {
writeln!(writer, " pop rax")?;
writeln!(writer, " xor rbx, rbx")?;
writeln!(writer, " mov bl, dword [rax]")?;
writeln!(writer, " push rbx")?;
ti += 1;
}
InstructionType::Store32 => {
writeln!(writer, " pop rbx")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " mov dword[rax], bl")?;
ti += 1;
}
InstructionType::Load64 => {
writeln!(writer, " pop rax")?;
writeln!(writer, " xor rbx, rbx")?;
writeln!(writer, " mov bl, qword [rax]")?;
writeln!(writer, " push rbx")?;
ti += 1;
}
InstructionType::Store64 => {
writeln!(writer, " pop rbx")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " mov qword [rax], bl")?;
ti += 1; ti += 1;
} }
// math // math
InstructionType::Plus => { InstructionType::Plus => {
writeln!(writer, " ;; -- plus")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
writeln!(writer, " add rax, rbx")?; writeln!(writer, " add rax, rbx")?;
@ -179,7 +228,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Minus => { InstructionType::Minus => {
writeln!(writer, " ;; -- minus")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
writeln!(writer, " sub rbx, rax")?; writeln!(writer, " sub rbx, rax")?;
@ -187,7 +235,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Equals => { InstructionType::Equals => {
writeln!(writer, " ;; -- equals")?;
writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rcx, 0")?;
writeln!(writer, " mov rdx, 1")?; writeln!(writer, " mov rdx, 1")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
@ -198,7 +245,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Lt => { InstructionType::Lt => {
writeln!(writer, " ;; -- lt")?;
writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rcx, 0")?;
writeln!(writer, " mov rdx, 1")?; writeln!(writer, " mov rdx, 1")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
@ -209,7 +255,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Gt => { InstructionType::Gt => {
writeln!(writer, " ;; -- gt")?;
writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rcx, 0")?;
writeln!(writer, " mov rdx, 1")?; writeln!(writer, " mov rdx, 1")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
@ -220,7 +265,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::NotEquals => { InstructionType::NotEquals => {
writeln!(writer, " ;; -- not equals")?;
writeln!(writer, " mov rcx, 1")?; writeln!(writer, " mov rcx, 1")?;
writeln!(writer, " mov rdx, 0")?; writeln!(writer, " mov rdx, 0")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
@ -231,7 +275,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Le => { InstructionType::Le => {
writeln!(writer, " ;; -- lt")?;
writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rcx, 0")?;
writeln!(writer, " mov rdx, 1")?; writeln!(writer, " mov rdx, 1")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
@ -242,7 +285,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Ge => { InstructionType::Ge => {
writeln!(writer, " ;; -- gt")?;
writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rcx, 0")?;
writeln!(writer, " mov rdx, 1")?; writeln!(writer, " mov rdx, 1")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
@ -253,7 +295,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Band => { InstructionType::Band => {
writeln!(writer, " ;; -- band")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
writeln!(writer, " and rbx, rax")?; writeln!(writer, " and rbx, rax")?;
@ -261,7 +302,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Bor => { InstructionType::Bor => {
writeln!(writer, " ;; -- bor")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
writeln!(writer, " or rbx, rax")?; writeln!(writer, " or rbx, rax")?;
@ -269,7 +309,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Shr => { InstructionType::Shr => {
writeln!(writer, " ;; -- shr")?;
writeln!(writer, " pop rcx")?; writeln!(writer, " pop rcx")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
writeln!(writer, " shr rbx, cl")?; writeln!(writer, " shr rbx, cl")?;
@ -277,7 +316,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Shl => { InstructionType::Shl => {
writeln!(writer, " ;; -- shl")?;
writeln!(writer, " pop rcx")?; writeln!(writer, " pop rcx")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
writeln!(writer, " shl rbx, cl")?; writeln!(writer, " shl rbx, cl")?;
@ -285,7 +323,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::DivMod => { InstructionType::DivMod => {
writeln!(writer, " ;; -- div")?;
writeln!(writer, " xor rdx, rdx")?; writeln!(writer, " xor rdx, rdx")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
@ -295,7 +332,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Mul => { InstructionType::Mul => {
writeln!(writer, " ;; -- mul")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?; writeln!(writer, " pop rbx")?;
writeln!(writer, " mul rbx")?; writeln!(writer, " mul rbx")?;
@ -303,14 +339,12 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Syscall0 => { InstructionType::Syscall0 => {
writeln!(writer, " ;; -- syscall0")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " syscall")?; writeln!(writer, " syscall")?;
writeln!(writer, " push rax")?; writeln!(writer, " push rax")?;
ti += 1; ti += 1;
}, },
InstructionType::Syscall1 => { InstructionType::Syscall1 => {
writeln!(writer, " ;; -- syscall1")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " pop rdi")?; writeln!(writer, " pop rdi")?;
writeln!(writer, " syscall")?; writeln!(writer, " syscall")?;
@ -318,7 +352,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Syscall2 => { InstructionType::Syscall2 => {
writeln!(writer, " ;; -- syscall2")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " pop rdi")?; writeln!(writer, " pop rdi")?;
writeln!(writer, " pop rsi")?; writeln!(writer, " pop rsi")?;
@ -327,7 +360,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Syscall3 => { InstructionType::Syscall3 => {
writeln!(writer, " ;; -- syscall3")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " pop rdi")?; writeln!(writer, " pop rdi")?;
writeln!(writer, " pop rsi")?; writeln!(writer, " pop rsi")?;
@ -338,7 +370,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Syscall4 => { InstructionType::Syscall4 => {
writeln!(writer, " ;; -- syscall4")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " pop rdi")?; writeln!(writer, " pop rdi")?;
writeln!(writer, " pop rsi")?; writeln!(writer, " pop rsi")?;
@ -349,7 +380,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Syscall5 => { InstructionType::Syscall5 => {
writeln!(writer, " ;; -- syscall5")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " pop rdi")?; writeln!(writer, " pop rdi")?;
writeln!(writer, " pop rsi")?; writeln!(writer, " pop rsi")?;
@ -361,7 +391,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::Syscall6 => { InstructionType::Syscall6 => {
writeln!(writer, " ;; -- syscall6")?;
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " pop rdi")?; writeln!(writer, " pop rdi")?;
writeln!(writer, " pop rsi")?; writeln!(writer, " pop rsi")?;
@ -374,14 +403,48 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1; ti += 1;
}, },
InstructionType::MemUse => { InstructionType::MemUse => {
writeln!(writer, " ;; -- MemUse")?;
writeln!(writer, " push mem_{}", token.addr.unwrap())?; writeln!(writer, " push mem_{}", token.addr.unwrap())?;
ti += 1; ti += 1;
}, },
InstructionType::None => unreachable!(), InstructionType::None => {
InstructionType::CastBool => ti += 1, println!("{token:?}");
InstructionType::CastPtr => ti += 1, unreachable!()
InstructionType::CastInt => ti += 1, },
InstructionType::FnCall => {
writeln!(writer, " call {}", token.text)?;
ti += 1;
},
InstructionType::Return => {
writeln!(writer, " sub rbp, 8")?;
writeln!(writer, " mov rbx, qword [rbp]")?;
writeln!(writer, " push rbx")?;
writeln!(writer, " ret")?;
ti += 1;
},
InstructionType::CastBool |
InstructionType::CastPtr |
InstructionType::CastInt |
InstructionType::CastVoid |
InstructionType::TypeBool |
InstructionType::TypePtr |
InstructionType::TypeInt |
InstructionType::TypeVoid |
InstructionType::TypeStr |
InstructionType::TypeAny |
InstructionType::Returns |
InstructionType::With => {
ti += 1;
}
InstructionType::ConstUse => {
writeln!(writer, " mov rax, qword [const_{}]", token.text)?;
writeln!(writer, " push rax")?;
let mut c = constants.get(&token.text).unwrap().clone();
c.used = true;
constants.remove(&token.text);
constants.insert(token.text.clone(), c);
ti += 1;
},
} }
} }
@ -390,48 +453,69 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
match keyword { match keyword {
// block // block
KeywordType::If => { KeywordType::If |
writeln!(writer, " ;; -- if")?; KeywordType::Do => {
writeln!(writer, " pop rax")?; writeln!(writer, " pop rax")?;
writeln!(writer, " test rax, rax")?; writeln!(writer, " test rax, rax")?;
writeln!(writer, " jz addr_{}", token.jmp)?; writeln!(writer, " jz addr_{}", token.jmp)?;
ti += 1; ti += 1;
}, }
KeywordType::Else => { KeywordType::Else => {
writeln!(writer, " ;; -- else")?;
writeln!(writer, " jmp addr_{}", token.jmp)?; writeln!(writer, " jmp addr_{}", token.jmp)?;
ti += 1; ti += 1;
}, },
KeywordType::While => { KeywordType::While => {
writeln!(writer, " ;; -- while")?;
ti += 1;
}
KeywordType::Do => {
writeln!(writer, " ;; -- do")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " test rax, rax")?;
writeln!(writer, " jz addr_{}", token.jmp)?;
ti += 1; ti += 1;
} }
KeywordType::End => { KeywordType::End => {
writeln!(writer, " ;; -- end")?;
if ti + 1 != token.jmp { if ti + 1 != token.jmp {
writeln!(writer, " jmp addr_{}", token.jmp)?; // writeln!(writer, " jmp addr_{}", token.jmp)?;
} }
ti += 1; ti += 1;
}, },
KeywordType::Memory => { KeywordType::Memory => {
memories.push((token.addr.unwrap(), token.value)); memories.push(Memory { size: token.value, loc: token.loc.clone(), id: token.addr.unwrap() });
ti += 1; ti += 1;
} }
KeywordType::Macro | KeywordType::ConstantDef => {
KeywordType::Include // TODO: after we add c style strings add supoort for them in constants
=> unreachable!() let a = args.get_opt_level()? < 1;
let c = Constant{
loc: token.loc.clone(),
name: token.text.clone(),
value_i: Some(token.value),
value_s: None,
used: a,
};
constants.insert(token.text.clone(), c);
ti += 1;
},
KeywordType::FunctionDef => {
writeln!(writer, "{}:", token.text)?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " mov qword [rbp], rbx")?;
writeln!(writer, " add rbp, 8")?;
functions.push(Function { loc: token.loc.clone(), name: token.text.clone() });
ti += 1;
},
KeywordType::FunctionDone => {
writeln!(writer, " sub rbp, 8")?;
writeln!(writer, " mov rbx, qword [rbp]")?;
writeln!(writer, " push rbx")?;
writeln!(writer, " ret")?;
ti += 1;
}
KeywordType::FunctionThen => ti += 1,
KeywordType::Function |
KeywordType::Include |
KeywordType::Constant => unreachable!(),
} }
} }
} }
} }
writeln!(writer, "addr_{ti}:")?; writeln!(writer, "addr_{ti}:")?;
writeln!(writer, "end:")?;
writeln!(writer, " mov rax, 60")?; writeln!(writer, " mov rax, 60")?;
writeln!(writer, " mov rdi, 0")?; writeln!(writer, " mov rdi, 0")?;
writeln!(writer, " syscall")?; writeln!(writer, " syscall")?;
@ -442,18 +526,65 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
writeln!(writer, " str_{}: db {} ; {}", i, s_list, s.escape_default())?; writeln!(writer, " str_{}: db {} ; {}", i, s_list, s.escape_default())?;
} }
writeln!(writer, "segment .bss")?; for (_, c) in constants {
for (_, s) in memories.iter().enumerate() { if !c.used {
writeln!(writer, " mem_{}: resb {}", s.0, s.1)?; continue;
}
if let Some(v) = &c.value_i {
writeln!(writer, " const_{}: dq {}", c.name, v)?;
} else if let Some(_v) = &c.value_s {
todo!();
} else {
unreachable!();
}
} }
writeln!(writer, " mem: resb {}", crate::compile::MEM_SZ)?;
writeln!(writer, "segment .bss")?;
for s in memories {
writeln!(writer, " mem_{}: resb {}", s.id, s.size)?;
}
writeln!(writer, " ret_stack: resq 256")?;
// for t in tokens {
// println!("{t:?}");
// }
writer.flush()?; writer.flush()?;
pre_compile_steps(
String::from_utf8_lossy(writer.buffer()).to_string().as_str(),
functions
)?;
linux_x86_64_compile_and_link(&of_a, &of_o, &of_c, args.quiet)?; linux_x86_64_compile_and_link(&of_a, &of_o, &of_c, args.quiet)?;
if args.run { if args.run {
let c = linux_x86_64_run(&of_c, &[], args.quiet)?; let c = linux_x86_64_run(&of_c, &[], args.quiet)?;
return Ok(c); return Ok(c);
} }
Ok(0) Ok(0)
}
fn pre_compile_steps(_code: &str, functions: Vec<Function>) -> Result<()> {
let mut has_main = false;
for func in functions {
if func.name == "main" {
has_main = true;
}
}
if !has_main {
crate::errors::missing_main_fn();
return Err(eyre!(""));
}
Ok(())
} }

View File

@ -1,5 +1,27 @@
use crate::constants::Loc;
pub mod linux_x86_64; pub mod linux_x86_64;
pub mod commands; pub mod commands;
pub const MEM_SZ: usize = 640 * 1000; // 4kb #[derive(Debug, Clone)]
pub const STRING_SZ: usize = 640 * 1000; // 4kb pub struct Constant {
pub loc: Loc,
pub name: String,
pub value_i: Option<usize>,
pub value_s: Option<String>,
pub used: bool
// extern: bool
}
#[derive(Debug, Clone)]
pub struct Memory {
pub size: usize,
pub loc: Loc,
pub id: usize
}
#[derive(Debug, Clone)]
pub struct Function {
pub loc: Loc,
pub name: String
}

20
src/config.rs Normal file
View File

@ -0,0 +1,20 @@
/**
* Prints out extra information
*/
pub const DEV_MODE: bool = true;
pub const DEFAULT_OUT_FILE: &str = "a.out";
pub const DEFAULT_INCLUDES: [&str;1] = [
"./include",
// "~/.mclang/include",
];
/**
* Interpreting configs
* `MEM_SZ` is the buffer size for memory
* `STRING_SZ` is the buffer size for strings
* if you have buffer overflow consider increasing these
*/
pub const MEM_SZ: usize = 640 * 1000; // 4kb
pub const STRING_SZ: usize = 640 * 1000; // 4kb

View File

@ -1,5 +1,4 @@
pub const ALLOW_MACRO_REDEFINITION: bool = true;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -33,9 +32,12 @@ pub enum InstructionType {
// mem // mem
Mem,
Load8, Load8,
Store8, Store8,
Load32,
Store32,
Load64,
Store64,
// syscalls // syscalls
Syscall0, Syscall0,
@ -49,21 +51,41 @@ pub enum InstructionType {
CastBool, CastBool,
CastPtr, CastPtr,
CastInt, CastInt,
CastVoid,
// typing
TypeBool,
TypePtr,
TypeInt,
TypeVoid,
TypeStr,
TypeAny,
Returns,
With,
FnCall,
MemUse, MemUse,
ConstUse,
Return,
None // Used for macros and any other non built in word definitions None // Used for macros and any other non built in word definitions
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum KeywordType { pub enum KeywordType {
If, If,
Else, Else,
End, End,
While, While,
Do, Do,
Macro,
Include, Include,
Memory Memory,
Constant,
ConstantDef,
Function,
FunctionDef,
FunctionThen,
FunctionDone
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -75,6 +97,7 @@ pub enum OpType {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Operator{ pub struct Operator{
pub typ: OpType, pub typ: OpType,
pub tok_typ: TokenType,
pub value: usize, pub value: usize,
pub text: String, //? only used for OpType::PushStr pub text: String, //? only used for OpType::PushStr
pub addr: Option<usize>, //? only used for OpType::PushStr pub addr: Option<usize>, //? only used for OpType::PushStr
@ -83,14 +106,15 @@ pub struct Operator{
} }
impl Operator { impl Operator {
pub fn new(typ: OpType, value: usize, text: String, file: String, row: usize, col: usize) -> Self { pub fn new(typ: OpType, tok_typ: TokenType, value: usize, text: String, file: String, row: usize, col: usize) -> Self {
Self { Self {
typ, typ,
value, value,
jmp: 0, jmp: 0,
addr: None, addr: None,
text, text,
loc: (file, row, col) loc: (file, row, col),
tok_typ,
} }
} }
pub fn set_addr(mut self, addr: usize) -> Self { pub fn set_addr(mut self, addr: usize) -> Self {
@ -108,7 +132,7 @@ impl OpType {
InstructionType::PushInt => "Number", InstructionType::PushInt => "Number",
InstructionType::PushStr => "String", InstructionType::PushStr => "String",
InstructionType::Print => "print", InstructionType::Print => "_dbg_print",
InstructionType::Dup => "dup", InstructionType::Dup => "dup",
InstructionType::Drop => "drop", InstructionType::Drop => "drop",
InstructionType::Rot => "rot", InstructionType::Rot => "rot",
@ -128,9 +152,12 @@ impl OpType {
InstructionType::Shl => "shl", InstructionType::Shl => "shl",
InstructionType::DivMod => "divmod", InstructionType::DivMod => "divmod",
InstructionType::Mul => "*", InstructionType::Mul => "*",
InstructionType::Mem => "mem", InstructionType::Load8 => "load8",
InstructionType::Load8 => "!8", InstructionType::Store8 => "store8",
InstructionType::Store8 => "@8", InstructionType::Load32 => "load32",
InstructionType::Store32 => "store32",
InstructionType::Load64 => "load64",
InstructionType::Store64 => "store64",
InstructionType::Syscall0 => "syscall0", InstructionType::Syscall0 => "syscall0",
InstructionType::Syscall1 => "syscall1", InstructionType::Syscall1 => "syscall1",
InstructionType::Syscall2 => "syscall2", InstructionType::Syscall2 => "syscall2",
@ -141,8 +168,20 @@ impl OpType {
InstructionType::CastBool => "cast(bool", InstructionType::CastBool => "cast(bool",
InstructionType::CastPtr => "cast(ptr)", InstructionType::CastPtr => "cast(ptr)",
InstructionType::CastInt => "cast(int)", InstructionType::CastInt => "cast(int)",
InstructionType::MemUse => "MemUse", InstructionType::CastVoid => "cast(void)",
InstructionType::None => "None", InstructionType::None => "None",
InstructionType::MemUse => "Memory use (internal)",
InstructionType::FnCall => "Function Call (Internal)",
InstructionType::ConstUse => "Constant Use (Internal)",
InstructionType::Return => "return",
InstructionType::TypeBool => "bool",
InstructionType::TypePtr => "ptr",
InstructionType::TypeInt => "int",
InstructionType::TypeVoid => "void",
InstructionType::TypeStr => "str",
InstructionType::Returns => "returns",
InstructionType::With => "with",
InstructionType::TypeAny => "any",
} }
} }
OpType::Keyword(keyword) => { OpType::Keyword(keyword) => {
@ -152,9 +191,14 @@ impl OpType {
KeywordType::End => "end", KeywordType::End => "end",
KeywordType::While => "while", KeywordType::While => "while",
KeywordType::Do => "do", KeywordType::Do => "do",
KeywordType::Macro => "macro",
KeywordType::Include => "include", KeywordType::Include => "include",
KeywordType::Memory => "memory" KeywordType::Memory => "memory",
KeywordType::Function => "fn",
KeywordType::Constant => "const",
KeywordType::FunctionThen => "then",
KeywordType::FunctionDone => "done",
KeywordType::ConstantDef => "constant Definition (internal)",
KeywordType::FunctionDef => "function definition (internal)"
} }
} }
@ -171,7 +215,7 @@ pub struct Token {
pub typ: TokenType, pub typ: TokenType,
pub value: Option<usize>, //* only used for Memories pub value: Option<usize>, //* only used for Memories
pub addr: Option<usize>, //* only used for Memories pub addr: Option<usize>, //* only used for Memories
pub op_typ: InstructionType //* only used for Memories pub op_typ: OpType //* only used for Memories
} }
#[derive(Debug, Clone, PartialEq, Copy)] #[derive(Debug, Clone, PartialEq, Copy)]
@ -210,6 +254,8 @@ pub enum Types {
Bool, Bool,
Ptr, Ptr,
Int, Int,
Void,
Str,
Any Any
// U8, // U8,
// U16, // U16,

18
src/errors/mod.rs Normal file
View File

@ -0,0 +1,18 @@
use crate::{error, help, code_block};
pub fn missing_main_fn() {
error!("Main function not found, please create one lol");
help!("Heres a basic main function with code that prints hello world:\n{}",
code_block!(
concat!(
"include \"std.mcl\"\n",
"\n",
"fn main with void retuns void then\n",
" \"Hello world!\\n\" puts\n",
"done\n"
)
)
);
}

View File

@ -1,9 +1,11 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::{constants::{OpType, Loc, InstructionType, KeywordType}, lerror, error}; use crate::{constants::{OpType, Loc, InstructionType, KeywordType, Operator}, lerror, error};
// use crate::util::logger; // use crate::util::logger;
use color_eyre::Result; use color_eyre::Result;
use eyre::eyre; use eyre::eyre;
use super::{Memory, Function, Constant};
mod syscalls; mod syscalls;
fn stack_pop(stack: &mut Vec<usize>, pos: &Loc) -> Result<usize> { fn stack_pop(stack: &mut Vec<usize>, pos: &Loc) -> Result<usize> {
@ -13,56 +15,66 @@ fn stack_pop(stack: &mut Vec<usize>, pos: &Loc) -> Result<usize> {
} }
} }
pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{ pub fn run(ops: &[crate::constants::Operator]) -> Result<i32>{
let mut stack: Vec<usize> = Vec::new(); let mut stack: Vec<usize> = Vec::new();
let mut ti = 0; let mut mem: Vec<u64> = vec![0; crate::MEM_SZ + crate::STRING_SZ];
let mut mem: Vec<u8> = vec![0; crate::compile::MEM_SZ + crate::compile::STRING_SZ];
let mut string_idx = 0; let mut string_idx = 0;
let prerunned = pre_run(ops);
let functions = prerunned.functions;
let constants = prerunned.constants;
let memories = prerunned.memories;
let mut memories: HashMap<usize, usize> = HashMap::new(); let mut ret_stack: Vec<usize> = Vec::new();
// for token in &tokens { // for token in &tokens {
// println!("{{typ: \"{:?}\", val: {}, jmp: {}}}", token.typ, token.value, token.jmp); // println!("{{typ: \"{:?}\", val: {}, jmp: {}}}", token.typ, token.value, token.jmp);
// } // }
while ti < tokens.len() {
let token = &tokens[ti]; // jump to main func
let pos = token.loc.clone(); let mut ip = if let Some(i) = functions.get("main") {i.id} else {
// println!("{:?}", token.typ); crate::errors::missing_main_fn();
match token.typ.clone() { return Err(eyre!(""));
};
while ip < ops.len() {
let op = &ops[ip];
let pos = op.loc.clone();
match op.typ.clone() {
OpType::Instruction(instruction) => { OpType::Instruction(instruction) => {
match instruction { match instruction {
InstructionType::PushInt => { InstructionType::PushInt => {
stack.push(token.value); stack.push(op.value);
ti += 1; ip += 1;
}, },
InstructionType::PushStr => { InstructionType::PushStr => {
if token.addr.is_none() { if op.addr.is_none() {
stack.push(token.text.len()); // string len stack.push(op.text.len()); // string len
stack.push(string_idx + crate::compile::MEM_SZ); stack.push(string_idx + crate::MEM_SZ);
for c in token.text.bytes() { for c in op.text.bytes() {
mem[crate::compile::MEM_SZ + string_idx] = c; mem[crate::MEM_SZ + string_idx] = u64::from(c);
string_idx += 1; string_idx += 1;
} }
} else { } else {
stack.push(token.text.len()); stack.push(op.text.len());
if let Some(addr) = token.addr { if let Some(addr) = op.addr {
stack.push(addr); stack.push(addr);
} }
} }
ti += 1; ip += 1;
}, },
InstructionType::Drop => { InstructionType::Drop => {
stack.pop(); stack.pop();
ti += 1; ip += 1;
}, },
InstructionType::Dup => { InstructionType::Dup => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
stack.push(a); stack.push(a);
stack.push(a); stack.push(a);
ti += 1; ip += 1;
}, },
InstructionType::Rot => { InstructionType::Rot => {
@ -72,14 +84,14 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
stack.push(b); stack.push(b);
stack.push(a); stack.push(a);
stack.push(c); stack.push(c);
ti += 1; ip += 1;
} }
InstructionType::Swap => { InstructionType::Swap => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(a); stack.push(a);
stack.push(b); stack.push(b);
ti += 1; ip += 1;
} }
InstructionType::Over => { InstructionType::Over => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
@ -87,43 +99,67 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
stack.push(b); stack.push(b);
stack.push(a); stack.push(a);
stack.push(b); stack.push(b);
ti += 1; ip += 1;
} }
InstructionType::Print => { InstructionType::Print => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
println!("{a}"); println!("{a}");
// let _ = io::stdout().flush(); // let _ = io::stdout().flush();
ti += 1; ip += 1;
}, },
// mem #[allow(clippy::cast_possible_truncation)]
InstructionType::Load8 |
InstructionType::Mem => { InstructionType::Load32 |
stack.push(0); InstructionType::Load64 => {
ti += 1;
}
InstructionType::Load8 => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
if a > crate::compile::MEM_SZ { if a > crate::MEM_SZ {
lerror!(&token.loc, "Invalid memory address {a}"); lerror!(&op.loc, "Invalid memory address {a}");
return Ok(1); return Ok(1);
} }
let byte = mem[a]; let byte = mem[a];
stack.push(byte as usize); stack.push(byte as usize);
ti += 1; ip += 1;
} }
#[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_possible_truncation)]
InstructionType::Store8 => { InstructionType::Store8 => {
let val = stack_pop(&mut stack, &pos)?; let val = stack_pop(&mut stack, &pos)?;
let addr = stack_pop(&mut stack, &pos)?; let addr = stack_pop(&mut stack, &pos)?;
if addr > crate::compile::MEM_SZ { if addr > crate::MEM_SZ {
lerror!(&token.loc, "Invalid memory address {addr}"); lerror!(&op.loc, "Invalid memory address {addr}");
return Ok(1); return Ok(1);
} }
mem[addr] = (val & 0xFF) as u8; mem[addr] = u64::from(val as u8);
ti += 1; ip += 1;
}
#[allow(clippy::cast_possible_truncation)]
InstructionType::Store32 => {
let val = stack_pop(&mut stack, &pos)?;
let addr = stack_pop(&mut stack, &pos)?;
if addr > crate::MEM_SZ {
lerror!(&op.loc, "Invalid memory address {addr}");
return Ok(1);
}
mem[addr] = u64::from(val as u32);
ip += 1;
}
#[allow(clippy::cast_possible_truncation)]
InstructionType::Store64 => {
let val = stack_pop(&mut stack, &pos)?;
let addr = stack_pop(&mut stack, &pos)?;
if addr > crate::MEM_SZ {
lerror!(&op.loc, "Invalid memory address {addr}");
return Ok(1);
}
mem[addr] = val as u64;
ip += 1;
} }
// math // math
@ -131,77 +167,77 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(b + a); stack.push(b + a);
ti += 1; ip += 1;
}, },
InstructionType::Minus => { InstructionType::Minus => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(b - a); stack.push(b - a);
ti += 1; ip += 1;
}, },
InstructionType::Equals => { InstructionType::Equals => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(usize::from(b == a)); stack.push(usize::from(b == a));
ti += 1; ip += 1;
}, },
InstructionType::Gt => { InstructionType::Gt => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(usize::from(b > a)); stack.push(usize::from(b > a));
ti += 1; ip += 1;
}, },
InstructionType::Lt => { InstructionType::Lt => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(usize::from(b < a)); stack.push(usize::from(b < a));
ti += 1; ip += 1;
}, },
InstructionType::NotEquals => { InstructionType::NotEquals => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(usize::from(b != a)); stack.push(usize::from(b != a));
ti += 1; ip += 1;
}, },
InstructionType::Ge => { InstructionType::Ge => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(usize::from(b >= a)); stack.push(usize::from(b >= a));
ti += 1; ip += 1;
}, },
InstructionType::Le => { InstructionType::Le => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(usize::from(b <= a)); stack.push(usize::from(b <= a));
ti += 1; ip += 1;
}, },
InstructionType::Band => { InstructionType::Band => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(a & b); stack.push(a & b);
ti += 1; ip += 1;
} }
InstructionType::Bor => { InstructionType::Bor => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(a | b); stack.push(a | b);
ti += 1; ip += 1;
} }
InstructionType::Shr => { InstructionType::Shr => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(b >> a); stack.push(b >> a);
ti += 1; ip += 1;
} }
InstructionType::Shl => { InstructionType::Shl => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(b << a); stack.push(b << a);
ti += 1; ip += 1;
} }
InstructionType::DivMod => { InstructionType::DivMod => {
@ -209,13 +245,13 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(b / a); stack.push(b / a);
stack.push(b % a); stack.push(b % a);
ti += 1; ip += 1;
} }
InstructionType::Mul => { InstructionType::Mul => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
let b = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?;
stack.push(b * a); stack.push(b * a);
ti += 1; ip += 1;
} }
InstructionType::Syscall0 => { InstructionType::Syscall0 => {
todo!(); todo!();
@ -245,7 +281,7 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
}; };
stack.push(ret); stack.push(ret);
// println!("{}", stack.len()); // println!("{}", stack.len());
ti += 1; ip += 1;
}, },
InstructionType::Syscall4 => { InstructionType::Syscall4 => {
todo!(); todo!();
@ -261,13 +297,41 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
}, },
InstructionType::MemUse => { InstructionType::MemUse => {
let m = memories.get(&token.addr.unwrap()).unwrap(); let m = memories.get(&op.addr.unwrap()).unwrap();
stack.push(*m); stack.push(m.id);
ti += 1; ip += 1;
}, },
InstructionType::CastBool => ti += 1, InstructionType::FnCall => {
InstructionType::CastPtr => ti += 1, ret_stack.push(ip);
InstructionType::CastInt => ti += 1, let f = functions.get(&op.text).unwrap();
ip = f.id;
}
InstructionType::Return => {
ip = ret_stack.pop().unwrap();
ip += 1;
}
InstructionType::ConstUse => {
let a = constants.get(&op.text).unwrap();
if let Some(i) = a.value_i {
stack.push(i);
} else if let Some(_s) = a.value_s.clone() {
unimplemented!();
}
ip += 1;
},
InstructionType::CastBool |
InstructionType::CastPtr |
InstructionType::CastInt |
InstructionType::CastVoid |
InstructionType::TypeBool |
InstructionType::TypePtr |
InstructionType::TypeInt |
InstructionType::TypeVoid |
InstructionType::TypeStr |
InstructionType::TypeAny |
InstructionType::Returns |
InstructionType::With => ip += 1,
InstructionType::None => unreachable!(), InstructionType::None => unreachable!(),
} }
@ -279,30 +343,42 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
if a == 0 { if a == 0 {
// println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp); // println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp);
ti = token.jmp; ip = op.jmp;
} else { } else {
ti += 1; ip += 1;
} }
}, },
KeywordType::Else | KeywordType::End => { KeywordType::Else | KeywordType::End => {
ti = token.jmp; ip = op.jmp;
}
KeywordType::While => {
ti += 1;
} }
KeywordType::Do => { KeywordType::Do => {
let a = stack.pop().unwrap(); let a = stack.pop().unwrap();
if a == 0 { if a == 0 {
ti = token.jmp; ip = op.jmp;
} else { } else {
ti += 1; ip += 1;
} }
} }
KeywordType::Memory => { KeywordType::While | //* exept this one, this one should just skip over
memories.insert(token.addr.unwrap(), token.value); KeywordType::Memory |
ti += 1; KeywordType::FunctionDef |
KeywordType::ConstantDef => {
//? Disabled since we now pre run the whole program
// constants.insert(op.text.clone(), Constant { loc: op.loc.clone(), name: op.text.clone(), value_i: Some(op.value), value_s: None, used: false });
ip += 1;
}, },
KeywordType::Macro | KeywordType::Include => unreachable!(), KeywordType::FunctionDone => {
if let Some(i) = ret_stack.pop() {
ip = i + 1;
} else {
break;
}
},
KeywordType::FunctionThen => ip += 1,
KeywordType::Constant |
KeywordType::Function |
KeywordType::Include => unreachable!(),
} }
} }
@ -311,4 +387,34 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
Ok(0) Ok(0)
}
pub struct Defineds {
pub memories: HashMap<usize, Memory>,
pub functions: HashMap<String, Function>,
pub constants: HashMap<String, Constant>
}
pub fn pre_run(ops: &[Operator]) -> Defineds {
let mut defineds = Defineds{
memories: HashMap::new(),
functions: HashMap::new(),
constants: HashMap::new(),
};
for (ip, op) in ops.iter().enumerate() {
match op.typ {
OpType::Keyword(KeywordType::Memory) => {
defineds.memories.insert(op.addr.unwrap(), Memory { size: op.value, loc: op.loc.clone(), id: op.addr.unwrap() });
},
OpType::Keyword(KeywordType::FunctionDef) => {
defineds.functions.insert(op.text.clone(), Function { loc: op.loc.clone(), name: op.text.clone(), id: ip });
},
OpType::Keyword(KeywordType::ConstantDef) => {
defineds.constants.insert(op.text.clone(), Constant { loc: op.loc.clone(), name: op.text.clone(), value_i: Some(op.value), value_s: None, used: false });
},
_ => ()
}
}
defineds
} }

View File

@ -1,10 +1,10 @@
#[allow(clippy::cast_possible_truncation)]
pub fn sys_write(sys_n: usize, fd: usize, buff: usize, count: usize, mem: &Vec<u8> ) -> usize { pub fn sys_write(sys_n: usize, fd: usize, buff: usize, count: usize, mem: &Vec<u64> ) -> usize {
let mem = (*mem).clone(); let mem = (*mem).clone();
// println!("{:?}", &mem[buff..(buff + count)]); // println!("{:?}", &mem[buff..(buff + count)]);
// return 0 ; // return 0 ;
let s = &mem[buff..(buff + count)].iter().map(|i| { let s = &mem[buff..(buff + count)].iter().map(|i| {
char::from_u32(u32::from(*i)).unwrap_or('_').to_string() char::from_u32(u32::from(*i as u8)).unwrap_or('_').to_string()
}).collect::<String>(); }).collect::<String>();
match fd { match fd {

View File

@ -1 +1,27 @@
pub mod linux_x86_64; use crate::constants::Loc;
pub mod linux_x86_64;
#[derive(Debug, Clone)]
pub struct Constant {
pub loc: Loc,
pub name: String,
pub value_i: Option<usize>,
pub value_s: Option<String>,
pub used: bool
// extern: bool
}
#[derive(Debug, Clone)]
pub struct Memory {
pub size: usize,
pub loc: Loc,
pub id: usize
}
#[derive(Debug, Clone)]
pub struct Function {
pub loc: Loc,
pub name: String,
pub id: usize
}

View File

@ -1,6 +1,5 @@
use crate::{constants::{Token, TokenType}, preprocessor::preprocess, Args}; use crate::{constants::{Token, TokenType}, Args};
use color_eyre::Result;
fn lex_word(s: String, tok_type: TokenType) -> (TokenType, String) { fn lex_word(s: String, tok_type: TokenType) -> (TokenType, String) {
match s { match s {
@ -89,7 +88,7 @@ fn lex_line(text: &str) -> Vec<(usize, String, TokenType)> {
tokens tokens
} }
pub fn lex<S: Into<String> + std::marker::Copy>(code: &str, file: S, args: &Args, preprocessing: bool) -> Result<Vec<Token>> { pub fn lex(code: &str, file: &str, _args: &Args) -> Vec<Token> {
let lines: Vec<(usize, &str)> = code let lines: Vec<(usize, &str)> = code
.split(['\n', '\r']) .split(['\n', '\r'])
.enumerate() .enumerate()
@ -104,14 +103,14 @@ pub fn lex<S: Into<String> + std::marker::Copy>(code: &str, file: S, args: &Args
for (col, tok, tok_type) in lt { for (col, tok, tok_type) in lt {
let (tok_type, tok) = lex_word(tok, tok_type); let (tok_type, tok) = lex_word(tok, tok_type);
let t = Token{ let t = Token{
file: file.into(), file: file.to_string(),
line: row + 1, line: row + 1,
col, col,
text: tok, text: tok,
typ: tok_type, typ: tok_type,
value: None, value: None,
addr: None, addr: None,
op_typ: crate::constants::InstructionType::None op_typ: crate::constants::OpType::Instruction(crate::constants::InstructionType::None)
}; };
tokens.push(t); tokens.push(t);
} }
@ -121,9 +120,7 @@ pub fn lex<S: Into<String> + std::marker::Copy>(code: &str, file: S, args: &Args
// for token in tokens.clone() { // for token in tokens.clone() {
// println!("tok: {:?}", token.text); // println!("tok: {:?}", token.text);
// } // }
if preprocessing {
tokens = preprocess(tokens, args)?;
}
Ok(tokens) tokens
} }

View File

@ -1,3 +1,5 @@
#![allow(clippy::wildcard_imports)]
#![allow(clippy::too_many_lines)]
mod constants; mod constants;
mod interpret; mod interpret;
mod util; mod util;
@ -7,18 +9,14 @@ mod lexer;
mod preprocessor; mod preprocessor;
mod typechecker; mod typechecker;
mod precompiler; mod precompiler;
mod config;
use std::fs; mod errors;
use config::*;
use std::{fs, collections::HashMap};
use clap::Parser; use clap::Parser;
use color_eyre::Result;
pub const DEFAULT_OUT_FILE: &str = "a.out"; use eyre::eyre;
pub const DEFAULT_INCLUDES: [&str;2] = [
"./include",
"~/.mclang/include",
];
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
#[command(author, version, about, long_about = None)] #[command(author, version, about, long_about = None)]
@ -53,38 +51,70 @@ pub struct Args {
/// Unsafe mode, disables typechecking /// Unsafe mode, disables typechecking
#[arg(long="unsafe", default_value_t = false)] #[arg(long="unsafe", default_value_t = false)]
unsaf: bool unsaf: bool,
/// Optimisation level, available levels: 'D': debug, '0': No optimisations
#[arg(long, short='O', default_value_t=String::from("0"))]
optimisation: String,
//#[arg(long, short='F')] //#[arg(long, short='F')]
//features: Vec<String>, //features: Vec<String>,
} }
fn main() { impl Args {
/// Get optimisation level
/// 0 => no optimisations
/// 1 => slight optimisations, mostly size ones
/// # Errors
///
/// Throws when the opt level is not known
pub fn get_opt_level(&self) -> Result<usize>{
match self.optimisation.as_str() {
"D" | "d" => Ok(0),
"0" | "" => Ok(1),
o => {
error!("Unknown optimisation level {o}");
Err(eyre!(""))
}
}
}
}
fn main() -> Result<()>{
let args = Args::parse(); let args = Args::parse();
let Ok(code) = fs::read_to_string(&args.in_file) else { let Ok(code) = fs::read_to_string(&args.in_file) else {
error!("Failed to read file {}, exiting!", &args.in_file); error!("Failed to read file {}, exiting!", &args.in_file);
return; return Ok(());
};
let Ok(tokens) = lexer::lex(&code, &args.in_file, &args, true) else {
error!("Lexing failed, exiting!");
return;
}; };
let tokens = lexer::lex(&code, args.in_file.as_str(), &args);
let mut parser = parser::Parser::new(tokens); let mut parser = parser::Parser::new(tokens, &args, None);
let Ok(tokens) = parser.parse() else { let tokens = match parser.parse(){
error!("Parsing failed, exiting!"); Ok(t) => t,
return; Err(e) => {
error!("Parsing failed, exiting!");
if crate::DEV_MODE {
return Err(e)
}
return Ok(());
}
}; };
let Ok(tokens) = typechecker::typecheck(&tokens, &args) else { match typechecker::typecheck(tokens.clone(), &args, None, HashMap::new(), HashMap::new()) {
error!("Typechecking failed, exiting!"); Ok(_) => (),
return; Err(e) => {
error!("Typechecking failed, exiting!");
if crate::DEV_MODE {
return Err(e);
}
return Ok(());
}
}; };
let c = if args.compile && args.interpret { let c = if args.compile && args.interpret {

View File

@ -1,22 +1,27 @@
use std::ops::Deref; use std::ops::Deref;
use crate::{constants::{Operator, OpType, Token, TokenType, Loc, KeywordType, InstructionType}, lerror}; use crate::{constants::{Operator, OpType, Token, TokenType, Loc, KeywordType, InstructionType}, lerror, preprocessor::Preprocessor, Args};
use color_eyre::Result; use color_eyre::Result;
use eyre::eyre; use eyre::eyre;
pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> { pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
let mut stack: Vec<usize> = Vec::new(); let mut stack: Vec<usize> = Vec::new();
for ip in 0..program.len() { for ip in 0..program.len() {
let op = &program.clone()[ip]; let op = &program.clone()[ip];
// println!("{op:?}");
match op.typ { match op.typ {
OpType::Keyword(KeywordType::If) | // OpType::Keyword(KeywordType::FunctionDef) |
OpType::Keyword(KeywordType::While) => { OpType::Keyword(KeywordType::If | KeywordType::While) => {
stack.push(ip); stack.push(ip);
} }
OpType::Keyword(KeywordType::Else) => { OpType::Keyword(KeywordType::Else) => {
let if_ip = stack.pop().unwrap(); let Some(if_ip) = stack.pop() else {
lerror!(&op.loc, "Unclosed-if else block");
return Err(eyre!("Cross referencing"));
};
if program[if_ip].typ != OpType::Keyword(KeywordType::If) { if program[if_ip].typ != OpType::Keyword(KeywordType::If) {
lerror!(&op.clone().loc,"'end' can only close 'if' blocks"); lerror!(&op.clone().loc,"'else' can only close 'if' blocks");
return Err(eyre!("Bad block")); return Err(eyre!("Bad block"));
} }
@ -24,26 +29,41 @@ pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
stack.push(ip); stack.push(ip);
}, },
OpType::Keyword(KeywordType::End) => { OpType::Keyword(KeywordType::End) => {
let block_ip = stack.pop().unwrap(); let Some(block_ip) = stack.pop() else {
lerror!(&op.loc, "Unclosed if, if-else, while-do, function, memory, or constant");
return Err(eyre!("Cross referencing"));
};
if program[block_ip].typ == OpType::Keyword(KeywordType::If) || match &program[block_ip].typ {
program[block_ip].typ == OpType::Keyword(KeywordType::Else) { OpType::Keyword(KeywordType::If | KeywordType::Else) => {
program[block_ip].jmp = ip;
program[block_ip].jmp = ip; program[ip].jmp = ip + 1;
program[ip].jmp = ip + 1; }
} else if program[block_ip].typ == OpType::Keyword(KeywordType::Do) { OpType::Keyword(KeywordType::Do) => {
program[ip].jmp = program[block_ip].jmp; program[ip].jmp = program[block_ip].jmp;
program[block_ip].jmp = ip + 1; program[block_ip].jmp = ip + 1;
} else { }
lerror!(&op.clone().loc,"'end' can only close 'if' blocks"); OpType::Keyword(KeywordType::FunctionThen) => {
return Err(eyre!("")); program[ip].typ = OpType::Instruction(InstructionType::Return);
}
OpType::Keyword(KeywordType::Memory | KeywordType::Constant) => (),
a => {
println!("{a:?}");
lerror!(&op.clone().loc,"'end' can only close if, if-else, while-do, function, memory, or constant blocks");
return Err(eyre!(""));
}
} }
} }
OpType::Keyword(KeywordType::Do) => { OpType::Keyword(KeywordType::Do) => {
let while_ip = stack.pop().unwrap(); let Some(block_ip) = stack.pop() else {
program[ip].jmp = while_ip; lerror!(&op.loc, "Unclosed while-do block");
return Err(eyre!("Cross referencing"));
};
program[ip].jmp = block_ip;
stack.push(ip); stack.push(ip);
} }
_ => () _ => ()
@ -51,21 +71,31 @@ pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
} }
if !stack.is_empty() { if !stack.is_empty() {
lerror!(&program[stack.pop().expect("Empy stack")].clone().loc,"Unclosed block"); // println!("{:?}", stack);
lerror!(&program[stack.pop().expect("Empy stack")].clone().loc,"Unclosed block, {:?}", program[stack.pop().expect("Empy stack")].clone());
return Err(eyre!("Unclosed block")); return Err(eyre!("Unclosed block"));
} }
Ok(program.clone()) Ok(program.clone())
} }
pub struct Parser { pub struct Parser<'a> {
tokens: Vec<Token> tokens: Vec<Token>,
pub preprocessor: Preprocessor<'a>,
#[allow(dead_code)]
args: &'a Args
} }
impl Parser { impl<'a> Parser<'a> {
pub fn new(file: Vec<Token>) -> Self { pub fn new(file: Vec<Token>, args: &'a Args, p: Option<Preprocessor<'a>>) -> Self {
let pre = if let Some(p) = p {p} else {
Preprocessor::new(Vec::new(), args)
};
Self{ Self{
tokens: file tokens: file,
preprocessor: pre,
args
} }
} }
@ -79,19 +109,19 @@ impl Parser {
let pos = (token.file.clone(), token.line, token.col); let pos = (token.file.clone(), token.line, token.col);
match token.typ { match token.typ {
TokenType::Word => { TokenType::Word => {
let word_type = if token.op_typ == InstructionType::MemUse { let word_type = if token.op_typ == OpType::Instruction(InstructionType::MemUse) {
OpType::Instruction(InstructionType::MemUse) OpType::Instruction(InstructionType::MemUse)
} else { } else {
lookup_word(&token.text, &pos) lookup_word(&token.text, &pos)
}; };
tokens.push(Operator::new(word_type, token.value.unwrap_or(0), token.text.clone(), token.file.clone(), token.line, token.col).set_addr(token.addr.unwrap_or(0))); tokens.push(Operator::new(word_type, token.typ, token.value.unwrap_or(0), token.text.clone(), token.file.clone(), token.line, token.col).set_addr(token.addr.unwrap_or(0)));
}, },
TokenType::Int => {// negative numbers not yet implemented TokenType::Int => {// negative numbers not yet implemented
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.text.parse::<usize>()?, String::new(), token.file.clone(), token.line, token.col)); tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.typ, token.text.parse::<usize>()?, String::new(), token.file.clone(), token.line, token.col));
}, },
TokenType::String => { TokenType::String => {
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushStr), 0, token.text.clone(), token.file.clone(), token.line, token.col)); tokens.push(Operator::new(OpType::Instruction(InstructionType::PushStr), token.typ, 0, token.text.clone(), token.file.clone(), token.line, token.col));
} }
TokenType::Char => { TokenType::Char => {
let c = token.text.clone(); let c = token.text.clone();
@ -100,27 +130,29 @@ impl Parser {
return Err(eyre!("")); return Err(eyre!(""));
} }
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.text.chars().next().unwrap() as usize, String::new(), token.file.clone(), token.line, token.col)); tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.typ, token.text.chars().next().unwrap() as usize, String::new(), token.file.clone(), token.line, token.col));
} }
}; };
//"print" => tokens.push(Operator::new(OpType::Print, 0, token.file.clone(), token.line, token.col)),
}
cross_ref(tokens) }
self.preprocessor.program = tokens;
let t = self.preprocessor.preprocess()?.get_ops();
let t = cross_ref(t)?;
Ok(t)
} }
} }
pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType { pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
let n = s.parse::<usize>(); let n = s.parse::<usize>();
if let Ok(_) = n { if n.is_ok() {
return OpType::Instruction(InstructionType::PushInt); return OpType::Instruction(InstructionType::PushInt);
} }
match s { match s {
//stack //stack
"print" => OpType::Instruction(InstructionType::Print), "_dbg_print" => OpType::Instruction(InstructionType::Print),
"dup" => OpType::Instruction(InstructionType::Dup), "dup" => OpType::Instruction(InstructionType::Dup),
"drop" => OpType::Instruction(InstructionType::Drop), "drop" => OpType::Instruction(InstructionType::Drop),
"rot" => OpType::Instruction(InstructionType::Rot), "rot" => OpType::Instruction(InstructionType::Rot),
@ -146,9 +178,12 @@ pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
// mem // mem
"mem" => OpType::Instruction(InstructionType::Mem),
"load8" => OpType::Instruction(InstructionType::Load8), "load8" => OpType::Instruction(InstructionType::Load8),
"store8" => OpType::Instruction(InstructionType::Store8), "store8" => OpType::Instruction(InstructionType::Store8),
"load32" => OpType::Instruction(InstructionType::Load32),
"store32" => OpType::Instruction(InstructionType::Store32),
"load64" => OpType::Instruction(InstructionType::Load64),
"store64" => OpType::Instruction(InstructionType::Store64),
"syscall0" => OpType::Instruction(InstructionType::Syscall0), "syscall0" => OpType::Instruction(InstructionType::Syscall0),
"syscall1" => OpType::Instruction(InstructionType::Syscall1), "syscall1" => OpType::Instruction(InstructionType::Syscall1),
@ -157,18 +192,31 @@ pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
"syscall4" => OpType::Instruction(InstructionType::Syscall4), "syscall4" => OpType::Instruction(InstructionType::Syscall4),
"syscall5" => OpType::Instruction(InstructionType::Syscall5), "syscall5" => OpType::Instruction(InstructionType::Syscall5),
"syscall6" => OpType::Instruction(InstructionType::Syscall6), "syscall6" => OpType::Instruction(InstructionType::Syscall6),
"cast(bool" => OpType::Instruction(InstructionType::CastBool), "cast(bool)" => OpType::Instruction(InstructionType::CastBool),
"cast(ptr)" => OpType::Instruction(InstructionType::CastPtr), "cast(ptr)" => OpType::Instruction(InstructionType::CastPtr),
"cast(int)" => OpType::Instruction(InstructionType::CastInt), "cast(int)" => OpType::Instruction(InstructionType::CastInt),
"cast(void)" => OpType::Instruction(InstructionType::CastVoid),
// block // block
"if" => OpType::Keyword(KeywordType::If), "if" => OpType::Keyword(KeywordType::If),
"else" => OpType::Keyword(KeywordType::Else), "else" => OpType::Keyword(KeywordType::Else),
"end" => OpType::Keyword(KeywordType::End), "end" => OpType::Keyword(KeywordType::End),
"while" => OpType::Keyword(KeywordType::While), "while" => OpType::Keyword(KeywordType::While),
"do" => OpType::Keyword(KeywordType::Do), "do" => OpType::Keyword(KeywordType::Do),
"macro" => OpType::Keyword(KeywordType::Macro),
"include" => OpType::Keyword(KeywordType::Include), "include" => OpType::Keyword(KeywordType::Include),
"memory" => OpType::Keyword(KeywordType::Memory), "memory" => OpType::Keyword(KeywordType::Memory),
"const" => OpType::Keyword(KeywordType::Constant),
"fn" => OpType::Keyword(KeywordType::Function),
"then" => OpType::Keyword(KeywordType::FunctionThen),
"done" => OpType::Keyword(KeywordType::FunctionDone),
"return" => OpType::Instruction(InstructionType::Return),
"returns" => OpType::Instruction(InstructionType::Returns),
"bool" => OpType::Instruction(InstructionType::TypeBool),
"int" => OpType::Instruction(InstructionType::TypeInt),
"ptr" => OpType::Instruction(InstructionType::TypePtr),
"void" => OpType::Instruction(InstructionType::TypeVoid),
"any" => OpType::Instruction(InstructionType::TypeAny),
"str" => OpType::Instruction(InstructionType::TypeStr),
"with" => OpType::Instruction(InstructionType::With),
_ => OpType::Instruction(InstructionType::None) _ => OpType::Instruction(InstructionType::None)
} }

View File

@ -2,7 +2,7 @@
use color_eyre::Result; use color_eyre::Result;
use eyre::eyre; use eyre::eyre;
use crate::{constants::{Token, OpType, InstructionType, Loc}, parser::lookup_word, lerror}; use crate::{constants::{ OpType, InstructionType, Loc, Operator}, lerror};
fn stack_pop(stack: &mut Vec<usize>, loc: &Loc) -> Result<usize> { fn stack_pop(stack: &mut Vec<usize>, loc: &Loc) -> Result<usize> {
if let Some(i) = stack.pop() { Ok(i) } else { if let Some(i) = stack.pop() { Ok(i) } else {
@ -11,23 +11,16 @@ fn stack_pop(stack: &mut Vec<usize>, loc: &Loc) -> Result<usize> {
} }
} }
pub fn precompile(tokens: &Vec<Token>) -> Result<Vec<usize>>{ pub fn precompile(tokens: &Vec<Operator>) -> Result<Vec<usize>>{
let mut stack: Vec<usize> = Vec::new(); let mut stack: Vec<usize> = Vec::new();
for token in tokens.iter() { for token in tokens.iter() {
let typ = lookup_word(&token.text, &token.loc()); match token.typ.clone() {
match typ {
OpType::Instruction(i) => { OpType::Instruction(i) => {
let loc = token.loc(); let loc = token.loc.clone();
match i { match i {
InstructionType::PushInt => { InstructionType::PushInt => {
if let Ok(i) = token.text.parse::<usize>() { stack.push(token.value);
stack.push(i);
} else {
lerror!(&token.loc(), "Bad number");
return Err(eyre!(""));
}
}, },
InstructionType::Plus => { InstructionType::Plus => {
let a = stack_pop(&mut stack, &loc)?; let a = stack_pop(&mut stack, &loc)?;
@ -136,14 +129,14 @@ pub fn precompile(tokens: &Vec<Token>) -> Result<Vec<usize>>{
stack.push(b); stack.push(b);
} }
_ => { _ => {
lerror!(&token.loc(), "Unsupported precompiler instruction {:?}", i); lerror!(&token.loc, "Unsupported precompiler instruction {:?}", i);
dbg!(tokens); dbg!(tokens);
return Err(eyre!("")); return Err(eyre!(""));
} }
} }
} }
_ => { OpType::Keyword(_) => {
lerror!(&token.loc(), "Unsupported precompiler keyword {:?}", typ); lerror!(&token.loc, "Unsupported precompiler keyword {:?}", token.typ);
dbg!(tokens); dbg!(tokens);
return Err(eyre!("")); return Err(eyre!(""));
} }

View File

@ -1,255 +1,475 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Deref;
use std::path::{PathBuf, Path}; use std::path::{PathBuf, Path};
use color_eyre::Result; use color_eyre::Result;
use eyre::eyre; use eyre::eyre;
use crate::constants::{Token, Loc, OpType, TokenType, KeywordType, InstructionType}; use crate::constants::{Loc, OpType, TokenType, KeywordType, InstructionType, Operator};
use crate::lexer::lex; use crate::lexer::lex;
use crate::precompiler::precompile; use crate::precompiler::precompile;
use crate::{lerror, lnote, Args, warn, linfo}; use crate::{lerror, Args, warn, linfo, parser};
use crate::parser::lookup_word; use crate::parser::lookup_word;
#[derive(Debug)]
pub struct Macro {
#[derive(Debug, Clone)]
pub struct Function {
pub loc: Loc, pub loc: Loc,
pub tokens: Vec<Token> pub name: String
} }
type Macros = HashMap<String, Macro>; #[derive(Debug, Clone)]
type Memories = HashMap<String, usize>; pub struct Constant {
pub loc: Loc,
pub name: String
}
pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{ #[derive(Debug, Clone)]
pub struct Memory {
pub loc: Loc,
pub id: usize
let mut program: Vec<Token> = Vec::new();
let mut macros: Macros = HashMap::new();
let mut memories: Memories = HashMap::new();
let mut rtokens = tokens;
rtokens.reverse();
while !rtokens.is_empty() {
let mut token = rtokens.pop().unwrap();
let op_type = lookup_word(&token.text, &token.loc());
match token.clone() {
_ if op_type == OpType::Keyword(KeywordType::Macro) => {
if rtokens.is_empty(){
lerror!(&token.loc(), "Macro name not found, expected {} but found nothing", TokenType::Word.human());
return Err(eyre!(""));
}
let macro_name = rtokens.pop().unwrap();
if macro_name.typ != TokenType::Word {
lerror!(&macro_name.loc(), "Bad macro name, expected {} but found {}", TokenType::Word.human(), macro_name.typ.human());
return Err(eyre!(""));
}
let word = lookup_word(&macro_name.text, &macro_name.loc());
if word != OpType::Instruction(InstructionType::None) {
lerror!(&macro_name.loc(), "Macro name cannot be a built in word, got '{}'", word.human());
return Err(eyre!(""));
}
if macros.get(&macro_name.text.clone()).is_some() && crate::constants::ALLOW_MACRO_REDEFINITION {
lerror!(&macro_name.loc(), "Macro redefinition is not allowed");
lnote!(&macros.get(&macro_name.text).unwrap().loc, "First definition here");
return Err(eyre!(""));
}
let mut macr = Macro{ loc: macro_name.loc(), tokens: Vec::new() };
let mut depth = 0;
while !rtokens.is_empty() {
let t = rtokens.pop().unwrap();
let typ = lookup_word(&t.text, &t.loc());
if typ == OpType::Keyword(KeywordType::End) && depth == 0 {
break;
} else if typ == OpType::Keyword(KeywordType::End) && depth != 0 {
depth -= 1;
macr.tokens.push(t);
} else if typ == OpType::Keyword(KeywordType::If) || typ == OpType::Keyword(KeywordType::Do) {
macr.tokens.push(t);
depth += 1;
} else {
macr.tokens.push(t);
}
}
macros.insert(macro_name.text, macr);
}
_ if op_type == OpType::Keyword(KeywordType::Include) => {
if rtokens.is_empty() {
lerror!(&token.loc(), "Include path not found, expected {} but found nothing", TokenType::String.human());
return Err(eyre!(""));
}
let include_path = rtokens.pop().unwrap();
if include_path.typ != TokenType::String {
lerror!(&include_path.loc(), "Bad include path, expected {} but found {}", TokenType::String.human(), include_path.typ.human());
return Err(eyre!(""));
}
let mut in_paths = args.include.clone();
in_paths.append(&mut crate::DEFAULT_INCLUDES.to_vec().clone().iter().map(|f| (*f).to_string()).collect::<Vec<String>>());
let mut include_code = String::new();
if include_path.text.chars().collect::<Vec<char>>()[0] == '.' {
let p = Path::new(include_path.file.as_str());
let p = p.parent().unwrap();
let p = p.join(&include_path.text);
include_code = std::fs::read_to_string(p)?;
} else {
for path in in_paths {
let p = PathBuf::from(path);
let p = p.join(&include_path.text);
if p.exists() {
include_code = std::fs::read_to_string(p)?;
}
}
}
if include_code.is_empty() {
lerror!(&include_path.loc(), "Include file in path '{}' was not found or is empty", include_path.text);
return Err(eyre!(""));
}
let mut code = lex(&include_code, &include_path.text, args, false)?;
code.reverse();
rtokens.append(&mut code);
}
_ if op_type == OpType::Keyword(KeywordType::Memory) => {
if rtokens.is_empty() {
lerror!(&token.loc(), "Memory name not found, expected {} but found nothing", TokenType::String.human());
return Err(eyre!(""));
}
let memory_name = rtokens.pop().unwrap();
if memory_name.typ != TokenType::Word {
lerror!(&memory_name.loc(), "Bad memory name, expected {} but found {}", TokenType::Word.human(), memory_name.typ.human());
return Err(eyre!(""));
}
if macros.get(&memory_name.text).is_some() {
lerror!(&memory_name.loc(), "Memory name cannot replace macro name, got {}", memory_name.text);
let m = macros.get(&memory_name.text).unwrap();
linfo!(&m.loc, "Macro found here");
return Err(eyre!(""));
}
let mut code: Vec<Token> = Vec::new();
let mut depth = 0;
while !rtokens.is_empty() {
let t = rtokens.pop().unwrap();
let typ = lookup_word(&t.text, &t.loc());
if typ == OpType::Keyword(KeywordType::End) && depth == 0 {
break;
} else if typ == OpType::Keyword(KeywordType::End) && depth != 0 {
depth -= 1;
code.push(t);
} else if typ == OpType::Keyword(KeywordType::If) || typ == OpType::Keyword(KeywordType::Do) {
code.push(t);
depth += 1;
} else {
code.push(t);
}
}
let res = precompile(&code)?;
if res.len() != 1 {
lerror!(&token.loc(), "Expected 1 number, got {:?}", res);
return Err(eyre!(""));
}
token.value = Some(res[0]);
token.addr = Some(memories.len());
program.push(token);
memories.insert(memory_name.text, memories.len());
}
_ => {
program.push(token);
}
}
}
//* Feel free to fix this horrifying shit
//* i wanna kms
let mut times = 0;
while program.iter().map(|f| {
if f.typ == TokenType::Word && f.op_typ != InstructionType::MemUse {
lookup_word(&f.text, &f.loc())
} else {
OpType::Instruction(InstructionType::PushInt) // i hate myself, this is a randomly picked optype so its happy and works
}
}).collect::<Vec<OpType>>().contains(&OpType::Instruction(InstructionType::None)){
if times >= 50 {
warn!("File import depth maxed out, if the program crashes try reducing the import depth, good luck youll need it");
break
}
program = expand(program, &macros, &memories)?;
times += 1;
}
Ok(program)
} }
pub fn expand(tokens: Vec<Token>, macros: &Macros, mems: &Memories) -> Result<Vec<Token>> { type Functions = HashMap<String, Function>;
let mut program: Vec<Token> = Vec::new(); type Memories = HashMap<String, Memory>;
type Constants = HashMap<String, Constant>;
let mut rtokens = tokens; #[derive(Debug, Clone)]
rtokens.reverse(); pub struct Preprocessor<'a> {
pub program: Vec<Operator>,
pub functions: Functions,
pub memories: Memories,
pub constants: Constants,
args: &'a Args
}
while !rtokens.is_empty() {
let op = rtokens.pop().unwrap(); impl<'a> Preprocessor<'a> {
let op_type = lookup_word(&op.text, &op.loc()); pub fn new(prog: Vec<Operator>, args: &'a Args) -> Self {
if op.typ == TokenType::Word { Self {
match op_type { program: prog,
OpType::Instruction(InstructionType::None) => { args,
let m = macros.get(&op.text); functions: HashMap::new(),
let mem = mems.get(&op.text); memories: HashMap::new(),
if let Some(m) = m { constants: HashMap::new(),
program.append(&mut m.tokens.clone()); }
} else }
if let Some(mem) = mem {
let mut t = op;
t.addr = Some(*mem); pub fn preprocess(&mut self) -> Result<&mut Preprocessor<'a>>{
t.op_typ = InstructionType::MemUse; // println!("pre: has do tokens: {:?}", self.program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::<Vec<Option<&Operator>>>());
program.push(t);
} let mut program: Vec<Operator> = Vec::new();
else {
lerror!(&op.loc(), "Unknown word '{}'", op.text.clone()); let mut rtokens = self.program.clone();
rtokens.reverse();
while !rtokens.is_empty() {
let mut token = rtokens.pop().unwrap();
// println!("{token:?}");
let op_type = token.typ.clone();
match token.clone() {
_ if op_type == OpType::Keyword(KeywordType::Include) => {
if rtokens.is_empty() {
lerror!(&token.loc, "Include path not found, expected {} but found nothing", TokenType::String.human());
return Err(eyre!("")); return Err(eyre!(""));
} }
let include_path = rtokens.pop().unwrap();
if include_path.tok_typ != TokenType::String {
lerror!(&include_path.loc, "Bad include path, expected {} but found {}", TokenType::String.human(), include_path.typ.human());
return Err(eyre!(""));
}
let mut in_paths = self.args.include.clone();
in_paths.append(&mut crate::DEFAULT_INCLUDES.to_vec().clone().iter().map(|f| (*f).to_string()).collect::<Vec<String>>());
let mut include_code = String::new();
let mut pth = PathBuf::new();
if include_path.text.chars().collect::<Vec<char>>()[0] == '.' {
let p = Path::new(include_path.loc.0.as_str());
let p = p.parent().unwrap();
let p = p.join(&include_path.text);
pth = p.clone();
include_code = std::fs::read_to_string(p)?;
} else {
for path in in_paths {
let p = PathBuf::from(path);
let p = p.join(&include_path.text);
pth = p.clone();
if p.exists() {
include_code = std::fs::read_to_string(p)?;
}
}
}
if include_code.is_empty() {
lerror!(&include_path.loc, "Include file in path '{}' was not found or is empty", include_path.text);
return Err(eyre!(""));
}
let a = pth.to_str().unwrap().to_string();
let code = lex(&include_code, a.as_str(), self.args);
let mut p = parser::Parser::new(code, self.args, Some(self.clone()));
let mut code = p.parse()?;
self.set_constants(p.preprocessor.get_constants());
self.set_functions(p.preprocessor.get_functions());
self.set_memories(p.preprocessor.get_memories());
code.reverse();
rtokens.append(&mut code);
} }
_ if op_type == OpType::Keyword(KeywordType::Memory) => {
if rtokens.is_empty() {
lerror!(&token.loc, "Memory name not found, expected {} but found nothing", TokenType::String.human());
return Err(eyre!(""));
}
let name = rtokens.pop().unwrap();
self.is_word_available(&name, KeywordType::Memory)?;
let mut code: Vec<Operator> = Vec::new();
let mut depth = 0;
while !rtokens.is_empty() {
let t = rtokens.pop().unwrap();
let typ = t.typ.clone();
if typ == OpType::Keyword(KeywordType::End) && depth == 0 {
break;
} else if typ == OpType::Keyword(KeywordType::End) && depth != 0 {
depth -= 1;
code.push(t);
} else if typ == OpType::Keyword(KeywordType::If) || typ == OpType::Keyword(KeywordType::Do) {
code.push(t);
depth += 1;
} else {
code.push(t);
}
}
let res = precompile(&code)?;
if res.len() != 1 {
lerror!(&token.loc, "Expected 1 number, got {:?}", res);
return Err(eyre!(""));
}
token.value = res[0];
token.addr = Some(self.memories.len());
program.push(token.clone());
self.memories.insert(name.text, Memory { loc: token.loc, id: self.memories.len() });
}
_ if op_type == OpType::Keyword(KeywordType::Function) => {
if rtokens.is_empty() {
lerror!(&token.loc, "Function name not found, expected {} but found nothing", TokenType::Word.human());
return Err(eyre!(""));
}
let mut name = rtokens.pop().unwrap();
if let '0'..='9' = name.text.chars().next().unwrap() {
lerror!(&name.loc, "Function name starts with a number which is not allowed");
return Err(eyre!(""));
}
// let mut should_warn = false;
for c in name.text.clone().chars() {
match c {
'a'..='z' |
'A'..='Z' |
'0'..='9' |
'-' | '_' => (),
'(' | ')' => {
name.text = name.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__");
}
_ => {
lerror!(&name.loc, "Function name contains '{c}', which is unsupported");
return Err(eyre!(""));
}
}
}
// if should_warn {
//TODO: add -W option in cli args to enable more warnings
//lwarn!(&function_name.loc, "Function name contains '(' or ')', this character is not supported but will be replaced with '__OP_PAREN__' or '__CL_PAREN__' respectively ");
// }
self.is_word_available(&name, KeywordType::Function)?;
self.functions.insert(name.text.clone(), Function{
loc: name.loc.clone(),
name: name.text.clone(),
});
let mut fn_def = token.clone();
fn_def.typ = OpType::Keyword(KeywordType::FunctionDef);
fn_def.text = name.text;
// println!("{:?}", token);
program.push(fn_def);
}
_ if op_type == OpType::Keyword(KeywordType::Constant) => {
if rtokens.is_empty() {
lerror!(&token.loc, "Constant name not found, expected {} but found nothing", TokenType::Word.human());
return Err(eyre!(""));
}
// println!("{token:?}");
let mut name = rtokens.pop().unwrap();
// let mut should_warn = false;
if let '0'..='9' = name.text.chars().next().unwrap() {
lerror!(&name.loc, "Constant name starts with a number which is not allowed");
return Err(eyre!(""));
}
for c in name.text.clone().chars() {
match c {
'a'..='z' |
'A'..='Z' |
'0'..='9' |
'-' | '_' => (),
'(' | ')' => {
// should_warn = true;
name.text = name.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__");
}
_ => {
lerror!(&name.loc, "Constant name contains '{c}', which is unsupported");
return Err(eyre!(""));
}
}
}
// if should_warn {
//TODO: add -W option in cli args to enable more warnings
//lwarn!(&name.loc, "Constant name contains '(' or ')', this character is not supported but will be replaced with '__OP_PAREN__' or '__CL_PAREN__' respectively ");
// }
self.is_word_available(&name, KeywordType::Constant)?;
self.constants.insert(name.text.clone(), Constant{
loc: name.loc.clone(),
name: name.text.clone(),
});
// println!("{:?}", self.constants);
let mut const_def = token.clone();
const_def.typ = OpType::Keyword(KeywordType::ConstantDef);
const_def.text = name.text;
let item = rtokens.pop().unwrap();
if item.tok_typ == TokenType::Int {
const_def.value = item.value;
} else {
lerror!(&token.loc, "For now only {:?} is allowed in constants", TokenType::Int);
return Err(eyre!(""));
}
let posibly_end = rtokens.pop();
// println!("end: {posibly_end:?}");
if posibly_end.is_none() || posibly_end.unwrap().typ != OpType::Keyword(KeywordType::End) {
lerror!(&token.loc, "Constant was not closed with an 'end' instruction, expected 'end' but found nothing");
return Err(eyre!(""));
}
// token.value =
program.push(const_def);
}
_ => { _ => {
program.push(op);
program.push(token);
} }
} }
} else {
program.push(op);
} }
self.program = program;
// println!("has do tokens: {:?}", self.program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::<Vec<Option<&Operator>>>());
//* Feel free to fix this horrifying shit
//* i wanna kms
let mut times = 0;
// dbg!(program.clone());
while self.program.iter().map(|f| {
if f.tok_typ == TokenType::Word &&
f.typ != OpType::Instruction(InstructionType::FnCall) &&
f.typ != OpType::Instruction(InstructionType::MemUse) &&
f.typ != OpType::Keyword(KeywordType::FunctionDef) &&
f.typ != OpType::Keyword(KeywordType::ConstantDef) &&
f.typ != OpType::Instruction(InstructionType::ConstUse) {
lookup_word(&f.text, &f.loc)
} else {
OpType::Instruction(InstructionType::PushInt) // i hate myself, this is a randomly picked optype so its happy and works
}
}).collect::<Vec<OpType>>().contains(&OpType::Instruction(InstructionType::None)){
if times >= 50 {
warn!("File import depth maxed out, if the program crashes try reducing the import depth, good luck youll need it");
break
}
self.expand()?;
times += 1;
}
Ok(self)
} }
pub fn expand(&mut self) -> Result<()> {
let mut program: Vec<Operator> = Vec::new();
// println!("{:?}", self.functions);
let mut rtokens = self.program.clone();
rtokens.reverse();
while !rtokens.is_empty() {
let op = rtokens.pop().unwrap();
let op_type = op.typ.clone();
if op.tok_typ == TokenType::Word {
match op_type {
OpType::Instruction(InstructionType::None) => {
let m = self.functions.get(&op.text);
let mem = self.memories.get(&op.text);
let cons = self.constants.get(&op.text);
if let Some(m) = m {
// println!("------ FOUND FUNCTION {} -----------", m.name);
let mut t = op.clone();
t.typ = OpType::Instruction(InstructionType::FnCall);
t.text = m.name.clone();
program.push(t.clone());
// println!("##### {:?}", t);
} else if let Some(mem) = mem {
let mut t = op.clone();
t.addr = Some(mem.deref().id);
t.typ = OpType::Instruction(InstructionType::MemUse);
program.push(t);
} else if let Some(cons) = cons {
let mut t = op.clone();
t.text = cons.deref().name.clone();
t.typ = OpType::Instruction(InstructionType::ConstUse);
program.push(t);
} else {
lerror!(&op.loc, "Preprocess: Unknown word '{}'", op.text.clone());
return Err(eyre!(""));
}
}
_ => {
program.push(op.clone());
}
}
} else {
program.push(op.clone());
}
// if op.typ == OpType::Keyword(KeywordType::Do) {
// println!("expand: {:?}", op);
// program.push(op.clone());
// }
}
// println!("expand: has do tokens: {:?}", program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::<Vec<Option<&Operator>>>());
self.program = program;
// println!("{:#?}", self.program);
// println!("{:?}", self.program.last().unwrap());
Ok(())
}
Ok(program)
pub fn get_ops(&mut self) -> Vec<Operator> {
self.program.clone()
}
pub fn is_word_available(&self, word: &Operator, typ: KeywordType) -> Result<bool> {
match typ {
KeywordType::Memory |
KeywordType::Constant |
KeywordType::Function => (),
_ => panic!()
}
if word.tok_typ != TokenType::Word {
lerror!(&word.loc, "Bad {typ:?}, expected {} but found {}", TokenType::Word.human(), word.typ.human());
if crate::DEV_MODE {println!("{word:?}")}
return Err(eyre!(""));
}
let w = lookup_word(&word.text, &word.loc);
if w != OpType::Instruction(InstructionType::None) {
lerror!(&word.loc, "Bad {typ:?}, {typ:?} definition cannot be builtin word, got {:?}", word.text);
if crate::DEV_MODE {println!("{word:?}")}
return Err(eyre!(""));
}
let m = self.memories.get(&word.text);
if let Some(m) = m {
if typ == KeywordType::Memory {
lerror!(&word.loc, "Memories cannot be redefined, got {}", word.text);
linfo!(&m.loc, "first definition here");
if crate::DEV_MODE {println!("{word:?}")}
return Err(eyre!(""));
}
lerror!(&word.loc, "{typ:?} cannot replace memory, got {}", word.text);
linfo!(&m.loc, "first definition here");
if crate::DEV_MODE {println!("{word:?}")}
return Err(eyre!(""));
}
let f = self.functions.get(&word.text);
if let Some(f) = f {
if typ == KeywordType::Function {
lerror!(&word.loc, "Functions cannot be redefined, got {}", word.text);
linfo!(&f.loc, "first definition here");
if crate::DEV_MODE {println!("{word:?}")}
return Err(eyre!(""));
}
lerror!(&word.loc, "{typ:?} cannot replace function, got {}", word.text);
linfo!(&f.loc, "first definition here");
if crate::DEV_MODE {println!("{word:?}")}
return Err(eyre!(""));
}
let c = self.constants.get(&word.text);
if let Some(c) = c {
if typ == KeywordType::Constant {
lerror!(&word.loc, "Constants cannot be redefined, got {}", word.text);
linfo!(&c.loc, "first definition here");
if crate::DEV_MODE {println!("{word:?}")}
return Err(eyre!(""));
}
lerror!(&word.loc, "{typ:?} cannot replace constant, got {}", word.text);
linfo!(&c.loc, "first definition here");
if crate::DEV_MODE {println!("{word:?}")}
return Err(eyre!(""));
}
Ok(true)
}
pub fn set_functions(&mut self, f: Functions) {
self.functions = f;
}
pub fn set_constants(&mut self, f: Constants) {
self.constants = f;
}
pub fn set_memories(&mut self, f: Memories) {
self.memories = f;
}
pub fn get_functions(&mut self) -> Functions {
self.functions.clone()
}
pub fn get_constants(&mut self) -> Constants {
self.constants.clone()
}
pub fn get_memories(&mut self) -> Memories{
self.memories.clone()
}
} }

View File

@ -1,35 +1,182 @@
use crate::{constants::{Operator, Types, OpType, KeywordType, InstructionType}, Args, lerror, warn}; use std::collections::HashMap;
use crate::{constants::{Operator, Types, OpType, KeywordType, InstructionType, Loc}, Args, lerror, warn};
use color_eyre::Result; use color_eyre::Result;
use eyre::eyre; use eyre::eyre;
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Function {
loc: Loc,
args: Vec<Types>,
returns: Vec<Types>,
}
pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{ #[derive(Debug, Clone)]
pub struct Constant {
#[allow(dead_code)]
loc: Loc,
types: Vec<Types>,
}
impl Function {
#[allow(dead_code)]
pub fn default() -> Self {
Self {
args: Vec::new(),
returns: Vec::new(),
loc: (String::new(), 0, 0)
}
}
}
type Functions = HashMap<String, Function>;
type Constants = HashMap<String, Constant>;
pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>, funcs: HashMap<String, Function>, consts: HashMap<String, Constant>) -> Result<(Vec<Types>, Functions, Constants)>{
if args.unsaf { if args.unsaf {
if !args.quiet { if !args.quiet {
warn!("Unsafe mode enabled, disabling typechecker, goodluck"); warn!("Unsafe mode enabled, disabling typechecker, goodluck");
} }
return Ok(ops.to_vec()); return Ok((Vec::new(), HashMap::new(), HashMap::new()));
} }
let mut stack: Vec<Types> = Vec::new(); let mut functions: HashMap<String, Function> = funcs;
let mut constants: HashMap<String, Constant> = consts;
for op in ops { // let mut in_function: (String, Function, Loc) = (String::new(), Function::default(), (String::new(), 0, 0));
let mut stack: Vec<Types> = if let Some(i) = init_types {i} else {Vec::new()};
let mut stack_snapshots: Vec<Vec<Types>> = Vec::new();
let mut rtokens = ops;
rtokens.reverse();
// println!("{:#?}", ops);
while !rtokens.is_empty() {
let op = rtokens.pop().unwrap();
// println!("{:?}", stack.clone());
// println!("{:?}", op);
// println!("{}", ops.len());
match op.typ.clone() { match op.typ.clone() {
OpType::Keyword(keyword) => { OpType::Keyword(keyword) => {
match keyword { match keyword {
KeywordType::If => { KeywordType::If |
stack_pop(&mut stack, &op, &[Types::Bool])?;
},
KeywordType::Do => { KeywordType::Do => {
stack_pop(&mut stack, &op, &[Types::Bool])?; stack_pop(&mut stack, &op, &[Types::Bool])?;
}, },
KeywordType::FunctionDef => {
let name = op.text.clone();
if let Some(p) = rtokens.pop() {
if p.typ != OpType::Instruction(InstructionType::With){
lerror!(&op.loc, "Expected {:?}, got {:?}", OpType::Instruction(InstructionType::With), p.typ);
return Err(eyre!(""));
}
} else {
lerror!(&op.loc, "Expected {:?}, got nothing", OpType::Instruction(InstructionType::With));
return Err(eyre!(""));
}
let mut p = rtokens.pop();
let mut func = Function {
args: Vec::new(),
returns: Vec::new(),
loc: op.loc
};
let mut return_args = false;
while p.as_ref().is_some() {
let op = p.as_ref().unwrap();
if op.typ == OpType::Instruction(InstructionType::TypeBool) ||
op.typ == OpType::Instruction(InstructionType::TypeInt) ||
op.typ == OpType::Instruction(InstructionType::TypePtr) ||
op.typ == OpType::Instruction(InstructionType::TypeAny) ||
op.typ == OpType::Instruction(InstructionType::TypeVoid) {
let t = if op.typ == OpType::Instruction(InstructionType::TypeInt) {
Types::Int
} else if op.typ == OpType::Instruction(InstructionType::TypeBool) {
Types::Bool
} else if op.typ == OpType::Instruction(InstructionType::TypePtr) {
Types::Ptr
} else if op.typ == OpType::Instruction(InstructionType::TypeVoid) {
if return_args {
func.returns = vec![Types::Void];
} else {
func.args = vec![Types::Void];
return_args = true;
continue;
}
Types::Void
} else if op.typ == OpType::Instruction(InstructionType::TypeStr) {
Types::Str
} else if op.typ == OpType::Instruction(InstructionType::TypeAny) {
Types::Any
} else {
panic!()
};
if return_args {
func.returns.push(t);
} else {
func.args.push(t);
}
}
if op.typ == OpType::Instruction(InstructionType::Returns) {
return_args = true;
}
if op.typ == OpType::Keyword(KeywordType::FunctionThen) {
break;
}
p = rtokens.pop();
};
let mut code: Vec<Operator> = Vec::new();
while !rtokens.is_empty() {
let op = rtokens.pop().unwrap();
if op.typ == OpType::Keyword(KeywordType::FunctionDone) {
break;
}
code.push(op);
}
let ts = if func.args.clone() == vec![Types::Void] {
Vec::new()
} else {
func.args.clone()
};
if ts.contains(&Types::Void) {
continue;
}
functions.insert(name.clone(), func.clone());
let (ret_typs, _, _) = typecheck(code, args, Some(ts.clone()), functions.clone(), constants.clone())?;
if ret_typs != func.returns && !func.returns.contains(&Types::Void){
lerror!(&func.loc, "Expected {:?}, but got {:?}", func.returns, ret_typs);
return Err(eyre!(""))
}
if !func.args.contains(&Types::Void) {
stack.append(&mut func.args);
}
stack_snapshots.push(stack.clone());
}
KeywordType::Else | KeywordType::Else |
KeywordType::End | KeywordType::End |
KeywordType::While | KeywordType::While |
KeywordType::Macro |
KeywordType::Include | KeywordType::Include |
KeywordType::Constant |
KeywordType::Memory => (), KeywordType::Memory => (),
KeywordType::ConstantDef => {
// println!("defined constant");
constants.insert(op.text, Constant { loc: op.loc.clone(), types: vec![Types::Int] });
},
KeywordType::FunctionThen |
KeywordType::FunctionDone |
KeywordType::Function => unreachable!(),
} }
}, },
OpType::Instruction(instruction) => { OpType::Instruction(instruction) => {
@ -73,85 +220,42 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
stack.push(a); stack.push(a);
stack.push(b); stack.push(b);
}, },
InstructionType::Minus => { InstructionType::Minus |
InstructionType::Plus |
InstructionType::Band |
InstructionType::Bor |
InstructionType::Shr |
InstructionType::Shl |
InstructionType::Mul => {
stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int])?; stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack.push(Types::Int); stack.push(Types::Int);
}, },
InstructionType::Plus => { InstructionType::Equals |
stack_pop(&mut stack, &op, &[Types::Int])?; InstructionType::Gt |
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?; InstructionType::Lt |
stack.push(Types::Int); InstructionType::Ge |
}, InstructionType::Le |
InstructionType::Equals => {
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack.push(Types::Bool);
},
InstructionType::Gt => {
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack.push(Types::Bool);
},
InstructionType::Lt => {
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack.push(Types::Bool);
},
InstructionType::Ge => {
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack.push(Types::Bool);
},
InstructionType::Le => {
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack.push(Types::Bool);
},
InstructionType::NotEquals => { InstructionType::NotEquals => {
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?; stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?; stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Bool); stack.push(Types::Bool);
}, },
InstructionType::Band => {
stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Int);
},
InstructionType::Bor => {
stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Int);
},
InstructionType::Shr => {
stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Int);
},
InstructionType::Shl => {
stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Int);
},
InstructionType::DivMod => { InstructionType::DivMod => {
stack_pop(&mut stack, &op, &[Types::Int])?; stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int])?; stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Int); stack.push(Types::Int);
stack.push(Types::Int); stack.push(Types::Int);
}, },
InstructionType::Mul => { InstructionType::Load8 |
stack_pop(&mut stack, &op, &[Types::Int])?; InstructionType::Load32 |
stack_pop(&mut stack, &op, &[Types::Int])?; InstructionType::Load64 => {
stack.push(Types::Int);
},
InstructionType::Mem => {
stack.push(Types::Ptr);
},
InstructionType::Load8 => {
stack_pop(&mut stack, &op, &[Types::Ptr])?; stack_pop(&mut stack, &op, &[Types::Ptr])?;
stack.push(Types::Int); stack.push(Types::Int);
}, },
InstructionType::Store8 => { InstructionType::Store8 |
InstructionType::Store32 |
InstructionType::Store64 => {
stack_pop(&mut stack, &op, &[Types::Int])?; stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Ptr])?; stack_pop(&mut stack, &op, &[Types::Ptr])?;
}, },
@ -216,16 +320,63 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?;
stack.push(Types::Int); stack.push(Types::Int);
}, },
InstructionType::CastVoid => {
stack_pop(&mut stack, &op, &[Types::Any])?;
stack.push(Types::Any);
},
InstructionType::MemUse => { InstructionType::MemUse => {
stack.push(Types::Ptr); stack.push(Types::Ptr);
}, },
InstructionType::None => {}, InstructionType::FnCall => {
stack_snapshots.push(stack.clone());
let f = functions.get(&op.text).unwrap().clone();
// in_function = (op.text.clone(), f.clone(), op.loc.clone());
let mut s = stack.clone();
let mut a = f.args.clone();
// s.reverse();
a.reverse();
for t in a{
if let Some(s2) = s.pop(){
if t != s2 {
lerror!(&op.loc, "Expected {:?}, but got {:?}", t, s2);
return Err(eyre!(""));
}
} else {
lerror!(&op.loc, "Expected {:?}, but got nothing", t);
return Err(eyre!(""));
}
}
}
InstructionType::Return |
InstructionType::None |
InstructionType::TypeBool |
InstructionType::TypePtr |
InstructionType::TypeInt |
InstructionType::TypeVoid |
InstructionType::TypeAny |
InstructionType::TypeStr |
InstructionType::Returns |
InstructionType::With => (),
InstructionType::ConstUse => {
// println!("{constants:?}");
let mut c = constants.get(&op.text).unwrap().clone();
stack.append(&mut c.types);
},
} }
}, },
} }
}
Ok(ops.to_vec())
}
Ok((stack, functions, constants))
} }

View File

@ -66,6 +66,21 @@ pub mod logger {
pub fn lnote<P: Deref<Target = Loc>>(loc: P, msg: &str) { pub fn lnote<P: Deref<Target = Loc>>(loc: P, msg: &str) {
println!("{f}:{r}:{c} {blue}note{rs}: {msg}", blue=color::FG_BLUE, rs=color::RESET, f=loc.0, r=loc.1, c=loc.2); println!("{f}:{r}:{c} {blue}note{rs}: {msg}", blue=color::FG_BLUE, rs=color::RESET, f=loc.0, r=loc.1, c=loc.2);
} }
pub fn help(msg: &str) {
println!("{blue}help{r}: {msg}", blue=color::FG_CYAN, r=color::RESET);
}
pub fn code_block(code: &str) -> String {
let mut ret = String::new();
let lines = code.lines();
for (i, line) in lines.enumerate() {
use std::fmt::Write;
writeln!(ret, "{}{} | {}{}",color::FG_BLUE, i + 1, line, color::RESET).unwrap();
}
ret
}
pub mod macros { pub mod macros {
#[macro_export] macro_rules! error { ($($arg:tt)*) => { $crate::util::logger::error(std::format_args!($($arg)*).to_string().as_str()) }; } #[macro_export] macro_rules! error { ($($arg:tt)*) => { $crate::util::logger::error(std::format_args!($($arg)*).to_string().as_str()) }; }
#[macro_export] macro_rules! warn { ($($arg:tt)*) => { $crate::util::logger::warn( std::format_args!($($arg)*).to_string().as_str()) }; } #[macro_export] macro_rules! warn { ($($arg:tt)*) => { $crate::util::logger::warn( std::format_args!($($arg)*).to_string().as_str()) }; }
@ -76,6 +91,9 @@ pub mod logger {
#[macro_export] macro_rules! lwarn { ($dst:expr, $($arg:tt)*) => { $crate::util::logger::lwarn($dst, std::format_args!($($arg)*).to_string().as_str()) }; } #[macro_export] macro_rules! lwarn { ($dst:expr, $($arg:tt)*) => { $crate::util::logger::lwarn($dst, std::format_args!($($arg)*).to_string().as_str()) }; }
#[macro_export] macro_rules! linfo { ($dst:expr, $($arg:tt)*) => { $crate::util::logger::linfo($dst, std::format_args!($($arg)*).to_string().as_str()) }; } #[macro_export] macro_rules! linfo { ($dst:expr, $($arg:tt)*) => { $crate::util::logger::linfo($dst, std::format_args!($($arg)*).to_string().as_str()) }; }
#[macro_export] macro_rules! lnote { ($dst:expr, $($arg:tt)*) => { $crate::util::logger::lnote($dst, std::format_args!($($arg)*).to_string().as_str()) }; } #[macro_export] macro_rules! lnote { ($dst:expr, $($arg:tt)*) => { $crate::util::logger::lnote($dst, std::format_args!($($arg)*).to_string().as_str()) }; }
#[macro_export] macro_rules! help { ($($arg:tt)*) => { $crate::util::logger::help( std::format_args!($($arg)*).to_string().as_str()) }; }
#[macro_export] macro_rules! code_block { ($($arg:tt)*) => { $crate::util::logger::code_block( std::format_args!($($arg)*).to_string().as_str()) }; }
} }
} }

View File

@ -1,6 +1,5 @@
memory m 10 end include "std.mcl"
m 69 store8 fn main with void returns void then
"hi\n" puts
done
m load8 print