diff --git a/editor/vscode/mclang-0.0.1.vsix b/editor/vscode/mclang-0.0.1.vsix deleted file mode 100644 index 9845bce..0000000 Binary files a/editor/vscode/mclang-0.0.1.vsix and /dev/null differ diff --git a/editor/vscode/mclang-0.0.2.vsix b/editor/vscode/mclang-0.0.2.vsix new file mode 100644 index 0000000..a81eedd Binary files /dev/null and b/editor/vscode/mclang-0.0.2.vsix differ diff --git a/editor/vscode/package.json b/editor/vscode/package.json index bae061c..90aeeec 100644 --- a/editor/vscode/package.json +++ b/editor/vscode/package.json @@ -2,7 +2,7 @@ "name": "mclang", "displayName": "mclang", "description": "Code highlighting for mclang", - "version": "0.0.1", + "version": "0.0.2", "repository": { "type": "git", "url": "git@github.com:mc-lang/mclang2.git" @@ -37,6 +37,6 @@ }, "dependencies": { "generator-code": "^1.7.4", - "vsce": "^2.15.0" + "@vscode/vsce": "^2.15.0" } } diff --git a/editor/vscode/syntaxes/mclang.tmLanguage.json b/editor/vscode/syntaxes/mclang.tmLanguage.json index 6fa3308..7fa7b7b 100644 --- a/editor/vscode/syntaxes/mclang.tmLanguage.json +++ b/editor/vscode/syntaxes/mclang.tmLanguage.json @@ -36,7 +36,11 @@ "patterns": [ { "name": "invalid.illegal", - "match": "(?<=^|\\s)(?:const|memory|fn)\\s+(end)(?:$|\\s)" + "match": "(?<=^|\\s)(?:const|memory)\\s+(end)(?:$|\\s)" + }, + { + "name": "invalid.illegal", + "match": "(?<=^|\\s)(?:fn)\\s+(done)(?:$|\\s)" }, { "name": "invalid.illegal", @@ -53,11 +57,11 @@ { "name": "keyword.declaration.mclang", - "match": "(?<=\\s|^)(macro|memory|fn|const|in|inline|include|assert|offset|addr-of|call-like|reset|int|ptr|bool|addr|--|let|peek)(?:\\s|$)" + "match": "(?<=\\s|^)(macro|memory|fn|const|in|inline|include|assert|offset|addr-of|call-like|reset|let|peek|with|returns)(?:\\s|$)" }, { "name": "keyword.control.mclang", - "match": "(?<=\\s|^)(if|else|elif|end|while|do|if\\*)(?:\\s|$)" + "match": "(?<=\\s|^)(if|else|elif|end|done|then|while|do|if\\*)(?:\\s|$)" } ] }, @@ -108,7 +112,7 @@ ] }, "comments": { - "patterns": [ + "disabled__patterns": [ { "name": "constant.other.character-class.regexp", "match": "(?://\\s*)(TODO(O*)|FIXME).*" @@ -123,7 +127,7 @@ "patterns": [ { "name": "variable.name.source.mclang", - "match": "(?<=^|\\s)(\\+|-|\\*|max|divmod|print|=|>|<|>=|<=|!=|>>|<<|\\||&|not|dup|swap|drop|over|rot|argc|argv|here|syscall0|syscall1|syscall2|syscall3|syscall4|syscall5|syscall6|mem|\\?\\?\\?)(?=>$|\\s)" + "match": "(?<=^|\\s)(\\+|-|\\*|int|ptr|bool|addr|any|void|max|divmod|_dbg_print|=|>|<|>=|<=|!=|>>|<<|\\||&|not|dup|swap|drop|over|rot|argc|argv|here|syscall0|syscall1|syscall2|syscall3|syscall4|syscall5|syscall6|\\?\\?\\?)(?=>$|\\s)" } ] }, @@ -135,7 +139,7 @@ }, { "name": "entity.name.function.mclang", - "match": "(?<=^|\\s)(NULL|true|false|cast(ptr)|cast(int)|cast(bool)|sizeof\\(u64\\)|sizeof\\(u32\\)|sizeof\\(ptr\\)|sizeof\\(bool\\)|sizeof\\(int\\)|sizeof\\(addr\\)|stdin|stdout|stderr|@ptr|@@ptr|@bool|@int|@addr|!bool|!ptr|!int|!addr|SYS_read|SYS_write|SYS_open|SYS_close|SYS_stat|SYS_fstat|SYS_lstat|SYS_poll|SYS_lseek|SYS_mmap|SYS_mprotect|SYS_munmap|SYS_brk|SYS_rt_sigaction|SYS_rt_sigprocmask|SYS_rt_sigreturn|SYS_ioctl|SYS_pread64|SYS_pwrite64|SYS_readv|SYS_writev|SYS_access|SYS_pipe|SYS_select|SYS_sched_yield|SYS_mremap|SYS_msync|SYS_mincore|SYS_madvise|SYS_shmget|SYS_shmat|SYS_shmctl|SYS_dup|SYS_dup2|SYS_pause|SYS_nanosleep|SYS_getitimer|SYS_alarm|SYS_setitimer|SYS_getpid|SYS_sendfile|SYS_socket|SYS_connect|SYS_accept|SYS_sendto|SYS_recvfrom|SYS_sendmsg|SYS_recvmsg|SYS_shutdown|SYS_bind|SYS_listen|SYS_getsockname|SYS_getpeername|SYS_socketpair|SYS_setsockopt|SYS_getsockopt|SYS_clone|SYS_fork|SYS_vfork|SYS_execve|SYS_exit|SYS_wait4|SYS_kill|SYS_uname|SYS_semget|SYS_semop|SYS_semctl|SYS_shmdt|SYS_msgget|SYS_msgsnd|SYS_msgrcv|SYS_msgctl|SYS_fcntl|SYS_flock|SYS_fsync|SYS_fdatasync|SYS_truncate|SYS_ftruncate|SYS_getdents|SYS_getcwd|SYS_chdir|SYS_fchdir|SYS_rename|SYS_mkdir|SYS_rmdir|SYS_creat|SYS_link|SYS_unlink|SYS_symlink|SYS_readlink|SYS_chmod|SYS_fchmod|SYS_chown|SYS_fchown|SYS_lchown|SYS_umask|SYS_gettimeofday|SYS_getrlimit|SYS_getrusage|SYS_sysinfo|SYS_times|SYS_ptrace|SYS_getuid|SYS_syslog|SYS_getgid|SYS_setuid|SYS_setgid|SYS_geteuid|SYS_getegid|SYS_setpgid|SYS_getppid|SYS_getpgrp|SYS_setsid|SYS_setreuid|SYS_setregid|SYS_getgroups|SYS_setgroups|SYS_setresuid|SYS_getresuid|SYS_setresgid|SYS_getresgid|SYS_getpgid|SYS_setfsuid|SYS_setfsgid|SYS_getsid|SYS_capget|SYS_capset|SYS_rt_sigpending|SYS_rt_sigtimedwait|SYS_rt_sigqueueinfo|SYS_rt_sigsuspend|SYS_sigaltstack|SYS_utime|SYS_mknod|SYS_uselib|SYS_personality|SYS_ustat|SYS_statfs|SYS_fstatfs|SYS_sysfs|SYS_getpriority|SYS_setpriority|SYS_sched_setparam|SYS_sched_getparam|SYS_sched_setscheduler|SYS_sched_getscheduler|SYS_sched_get_priority_max|SYS_sched_get_priority_min|SYS_sched_rr_get_interval|SYS_mlock|SYS_munlock|SYS_mlockall|SYS_munlockall|SYS_vhangup|SYS_modify_ldt|SYS_pivot_root|SYS__sysctl|SYS_prctl|SYS_arch_prctl|SYS_adjtimex|SYS_setrlimit|SYS_chroot|SYS_sync|SYS_acct|SYS_settimeofday|SYS_mount|SYS_umount2|SYS_swapon|SYS_swapoff|SYS_reboot|SYS_sethostname|SYS_setdomainname|SYS_iopl|SYS_ioperm|SYS_create_module|SYS_init_module|SYS_delete_module|SYS_get_kernel_syms|SYS_query_module|SYS_quotactl|SYS_nfsservctl|SYS_getpmsg|SYS_putpmsg|SYS_afs_syscall|SYS_tuxcall|SYS_security|SYS_gettid|SYS_readahead|SYS_setxattr|SYS_lsetxattr|SYS_fsetxattr|SYS_getxattr|SYS_lgetxattr|SYS_fgetxattr|SYS_listxattr|SYS_llistxattr|SYS_flistxattr|SYS_removexattr|SYS_lremovexattr|SYS_fremovexattr|SYS_tkill|SYS_time|SYS_futex|SYS_sched_setaffinity|SYS_sched_getaffinity|SYS_set_thread_area|SYS_io_setup|SYS_io_destroy|SYS_io_getevents|SYS_io_submit|SYS_io_cancel|SYS_get_thread_area|SYS_lookup_dcookie|SYS_epoll_create|SYS_epoll_ctl_old|SYS_epoll_wait_old|SYS_remap_file_pages|SYS_getdents64|SYS_set_tid_address|SYS_restart_syscall|SYS_semtimedop|SYS_fadvise64|SYS_timer_create|SYS_timer_settime|SYS_timer_gettime|SYS_timer_getoverrun|SYS_timer_delete|SYS_clock_settime|SYS_clock_gettime|SYS_clock_getres|SYS_clock_nanosleep|SYS_exit_group|SYS_epoll_wait|SYS_epoll_ctl|SYS_tgkill|SYS_utimes|SYS_vserver|SYS_mbind|SYS_set_mempolicy|SYS_get_mempolicy|SYS_mq_open|SYS_mq_unlink|SYS_mq_timedsend|SYS_mq_timedreceive|SYS_mq_notify|SYS_mq_getsetattr|SYS_kexec_load|SYS_waitid|SYS_add_key|SYS_request_key|SYS_keyctl|SYS_ioprio_set|SYS_ioprio_get|SYS_inotify_init|SYS_inotify_add_watch|SYS_inotify_rm_watch|SYS_migrate_pages|SYS_openat|SYS_mkdirat|SYS_mknodat|SYS_fchownat|SYS_futimesat|SYS_newfstatat|SYS_unlinkat|SYS_renameat|SYS_linkat|SYS_symlinkat|SYS_readlinkat|SYS_fchmodat|SYS_faccessat|SYS_pselect6|SYS_ppoll|SYS_unshare|SYS_set_robust_list|SYS_get_robust_list|SYS_splice|SYS_tee|SYS_sync_file_range|SYS_vmsplice|SYS_move_pages|SYS_utimensat|SYS_epoll_pwait|SYS_signalfd|SYS_timerfd_create|SYS_eventfd|SYS_fallocate|SYS_timerfd_settime|SYS_timerfd_gettime|SYS_accept4|SYS_signalfd4|SYS_eventfd2|SYS_epoll_create1|SYS_dup3|SYS_pipe2|SYS_inotify_init1|SYS_preadv|SYS_pwritev|SYS_rt_tgsigqueueinfo|SYS_perf_event_open|SYS_recvmmsg|SYS_fanotify_init|SYS_fanotify_mark|SYS_prlimit64|SYS_name_to_handle_at|SYS_open_by_handle_at|SYS_clock_adjtime|SYS_syncfs|SYS_sendmmsg|SYS_setns|SYS_getcpu|SYS_process_vm_readv|SYS_process_vm_writev|SYS_kcmp|SYS_finit_module|AT_FDCWD|O_RDONLY|O_WRONLY|O_RDWR|O_CREAT|O_TRUNC|O_NONBLOCK|F_SETFL|F_GETFL|EAGAIN|CLOCK_MONOTONIC|TIMER_ABSTIME|MAP_PRIVATE|MAP_ANONYMOUS|PROT_READ|PROT_WRITE|SIGQUIT|timespec\\.tv_sec|timespec\\.tv_nsec|sizeof\\(timespec\\)|ptr\\+|ptr-|ptr!=|ptr=|ptr<|\\+ptr|ptr-diff|sizeof\\(stat\\)|stat\\.st_dev|stat\\.st_ino|stat\\.st_mode|stat\\.st_nlink|stat\\.st_uid|stat\\.st_gid|stat\\.st_rdev|stat\\.st_size|@stat\\.st_size|stat\\.st_blksize|stat\\.st_blocks|stat\\.st_atim|stat\\.st_mtim|stat\\.st_ctim|sizeof\\(stat\\.st_dev\\)|sizeof\\(stat\\.st_ino\\)|sizeof\\(stat\\.st_mode\\)|sizeof\\(stat\\.st_nlink\\)|sizeof\\(stat\\.st_uid\\)|sizeof\\(stat\\.st_gid\\)|sizeof\\(stat\\.st_rdev\\)|sizeof\\(stat\\.st_size\\)|sizeof\\(stat\\.st_blksize\\)|sizeof\\(stat\\.st_blocks\\)|sizeof\\(stat\\.st_atim\\)|sizeof\\(stat\\.st_mtim\\)|sizeof\\(stat\\.st_ctim\\)|write|read|openat|fstat|stat|close|exit|mmap|clock_nanosleep|clock_gettime|fork|getpid|execve|wait4|rename|fcntl|kill|dup2|/|%|mod|div|imod|idiv|emod|nth_argv|lnot|land|lor|inc64-by|inc64|dec64|inc32|dec32|inc8|dec8|swap64|cstrlen|cstreq|cstr-to-str|fputs|puts|eputs|WIFSTOPPED|WIFCONTINUED|WIFSIGNALED|WTERMSIG|WIFEXITED|WEXITSTATUS|offsetof\\(Str\\.count\\)|offsetof\\(Str\\.data\\)|sizeof\\(Str\\)|Str\\.count|Str\\.data|@Str\\.count|@Str\\.data|!Str\\.count|!Str\\.data|@Str|!Str|str-chop-one-left|str-chop-one-right|\\?space|str-trim-left|str-chop-by-predicate|str-chop-by-delim|str-starts-with|\\?str-empty|streq|\\?digit|isdigit|\\?alpha|isalpha|\\?alnum|isalnum|try-parse-int|PUTU_BUFFER_CAP|fputu|fput0u|putu|put0u|eputu|memcpy|memset|srand|RAND_A|RAND_C|rand|getenv|TMP_CAP|tmp-clean|tmp-end|tmp-rewind|tmp-alloc|tmp-str-to-cstr|tmp-append|tmp-append-ptr|execvp|append-item|tmp-utos|map-file|\\?file-exist|\\?shell-safe-char|\\?shell-safe-str|shell-escape|timeit/from-here|1e9|timeit/to-here|str-rfind|dirname|putch|remove-ext|cmd-echoed)(?:\\s|$)" + "match": "(?<=^|\\s)(NULL|true|false|cast(ptr)|cast(int)|cast(bool)|sizeof\\(u64\\)|sizeof\\(u32\\)|sizeof\\(ptr\\)|sizeof\\(bool\\)|sizeof\\(int\\)|sizeof\\(addr\\)|STDIN|STDOUT|STDERR|@ptr|@@ptr|@bool|@int|@addr|!bool|!ptr|!int|!addr|AT_FDCWD|O_RDONLY|O_WRONLY|O_RDWR|O_CREAT|O_TRUNC|O_NONBLOCK|F_SETFL|F_GETFL|EAGAIN|CLOCK_MONOTONIC|TIMER_ABSTIME|MAP_PRIVATE|MAP_ANONYMOUS|PROT_READ|PROT_WRITE|SIGQUIT|timespec\\.tv_sec|timespec\\.tv_nsec|sizeof\\(timespec\\)|ptr\\+|ptr-|ptr!=|ptr=|ptr<|\\+ptr|ptr-diff|sizeof\\(stat\\)|stat\\.st_dev|stat\\.st_ino|stat\\.st_mode|stat\\.st_nlink|stat\\.st_uid|stat\\.st_gid|stat\\.st_rdev|stat\\.st_size|@stat\\.st_size|stat\\.st_blksize|stat\\.st_blocks|stat\\.st_atim|stat\\.st_mtim|stat\\.st_ctim|sizeof\\(stat\\.st_dev\\)|sizeof\\(stat\\.st_ino\\)|sizeof\\(stat\\.st_mode\\)|sizeof\\(stat\\.st_nlink\\)|sizeof\\(stat\\.st_uid\\)|sizeof\\(stat\\.st_gid\\)|sizeof\\(stat\\.st_rdev\\)|sizeof\\(stat\\.st_size\\)|sizeof\\(stat\\.st_blksize\\)|sizeof\\(stat\\.st_blocks\\)|sizeof\\(stat\\.st_atim\\)|sizeof\\(stat\\.st_mtim\\)|sizeof\\(stat\\.st_ctim\\)|write|read|openat|fstat|stat|close|exit|mmap|clock_nanosleep|clock_gettime|fork|getpid|execve|wait4|rename|fcntl|kill|dup2|/|%|mod|div|imod|idiv|emod|nth_argv|lnot|land|lor|inc64-by|inc64|dec64|inc32|dec32|inc8|dec8|swap64|cstrlen|cstreq|cstr-to-str|fputs|puts|eputs|WIFSTOPPED|WIFCONTINUED|WIFSIGNALED|WTERMSIG|WIFEXITED|WEXITSTATUS|offsetof\\(Str\\.count\\)|offsetof\\(Str\\.data\\)|sizeof\\(Str\\)|Str\\.count|Str\\.data|@Str\\.count|@Str\\.data|!Str\\.count|!Str\\.data|@Str|!Str|str-chop-one-left|str-chop-one-right|\\?space|str-trim-left|str-chop-by-predicate|str-chop-by-delim|str-starts-with|\\?str-empty|streq|\\?digit|isdigit|\\?alpha|isalpha|\\?alnum|isalnum|try-parse-int|PUTU_BUFFER_CAP|fputu|fput0u|putu|put0u|eputu|memcpy|memset|srand|RAND_A|RAND_C|rand|getenv|TMP_CAP|tmp-clean|tmp-end|tmp-rewind|tmp-alloc|tmp-str-to-cstr|tmp-append|tmp-append-ptr|execvp|append-item|tmp-utos|map-file|\\?file-exist|\\?shell-safe-char|\\?shell-safe-str|shell-escape|timeit/from-here|1e9|timeit/to-here|str-rfind|dirname|putch|remove-ext|cmd-echoed)(?:\\s|$)" } ] } diff --git a/include/compat.mcl b/include/compat.mcl new file mode 100644 index 0000000..1d19a26 --- /dev/null +++ b/include/compat.mcl @@ -0,0 +1 @@ +// todo: add some sort of macrow \ No newline at end of file diff --git a/include/fs.mcl b/include/fs.mcl index 2060661..3268996 100644 --- a/include/fs.mcl +++ b/include/fs.mcl @@ -1,19 +1,18 @@ - -macro FS_O_APPEND 1024 end // append to existing file -macro FS_O_ASYNC 8192 end // use signal-driven IO -macro FS_O_CLOEXEC 524288 end // use close-on-exec (avoid race conditions and lock contentions) -macro FS_O_CREAT 64 end // create file if it doesn’t exist -macro FS_O_DIRECT 16384 end // bypass cache (slower) -macro FS_O_DIRECTORY 65536 end // fail if pathname isn’t a directory -macro FS_O_DSYNC 4096 end // ensure output is sent to hardware and metadata written before return -macro FS_O_EXCL 128 end // ensure creation of file -macro FS_O_LARGEFILE 0 end // allows use of file sizes represented by off64_t -macro FS_O_NOATIME 262144 end // do not increment access time upon open -macro FS_O_NOCTTY 256 end // if pathname is a terminal device, don’t become controlling terminal -macro FS_O_NOFOLLOW 131072 end // fail if pathname is symbolic link -macro FS_O_NONBLOCK 2048 end // if possible, open file with non-blocking IO -macro FS_O_NDELAY 2048 end // same as O_NONBLOCK -macro 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_SYNC 1052672 end // wait for IO to complete before returning -macro FS_O_TMPFILE 4259840 end // create an unnamed, unreachable (via any other open call) temporary file -macro FS_O_TRUNC 512 end // if file exists, ovewrite it (careful!) +const FS_O_APPEND 1024 end // append to existing file +const 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) +const FS_O_CREAT 64 end // create file if it doesn’t exist +const FS_O_DIRECT 16384 end // bypass cache (slower) +const FS_O_DIRECTORY 65536 end // fail if pathname isn’t a directory +const 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 +const 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 +const FS_O_NOCTTY 256 end // if pathname is a terminal device, don’t become controlling terminal +const 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 +const 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 +const 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 +const FS_O_TRUNC 512 end // if file exists, ovewrite it (careful!) diff --git a/include/int.mcl b/include/int.mcl index c74ee7e..d6e6f94 100644 --- a/include/int.mcl +++ b/include/int.mcl @@ -1,16 +1,15 @@ -macro NULL 0 end -macro false 0 end -macro true 1 end +const NULL 0 end +const false 0 end +const true 1 end -macro div divmod drop end -macro mod divmod swap drop end -macro / div end -macro % mod end +fn div with int int returns int then divmod drop done +fn mod with int int returns int then divmod swap drop done -macro 2dup over over end -macro 2drop drop drop end -macro sizeof(u64) 8 end -macro sizeof(u32) 4 end -macro sizeof(u16) 2 end -macro sizeof(u8) 1 end \ No newline at end of file +fn dup2 with any any returns any any any any then over over done +fn drop2 with any any returns void then drop drop done + +const sizeof(u64) 8 end +const sizeof(u32) 4 end +const sizeof(u16) 2 end +const sizeof(u8) 1 end \ No newline at end of file diff --git a/include/io.mcl b/include/io.mcl index 76b7ae5..0363c02 100644 --- a/include/io.mcl +++ b/include/io.mcl @@ -5,9 +5,9 @@ // @arg buff_ptr: Ptr - pointer to the buffer to write // @arg fd: Int - file descriptor // @ret Int -macro write +fn write with int ptr int returns int then SYS_write syscall3 -end +done // Write to a file descriptor using the SYS_write syscall // args: [buff_size, buff_ptr, fd] @@ -15,9 +15,9 @@ end // @arg buff_ptr: Ptr - pointer to the buffer to write // @arg fd: Int - file descriptor // @ret Int -macro read +fn read with int ptr int returns int then SYS_read syscall3 -end +done // Print a string to STDOUT @@ -25,18 +25,18 @@ end // @arg buff_size: Int - number of bytes to write // @arg buff_ptr: Ptr - pointer to the buffer to write // @ret NULL -macro puts +fn puts with int ptr returns void then STDOUT write drop -end +done // Print a string to STDERR // args: [str_size, str_ptr] // @arg buff_size: Int - number of bytes to write // @arg buff_ptr: Ptr - pointer to the buffer to write // @ret NULL -macro eputs +fn eputs with int ptr returns void then STDOUT write drop -end +done // TODO: make putc and eputc after we make local mem @@ -44,7 +44,7 @@ end // args: [exit_code] // @arg exit_code: Int // @ret NULL/NEVER -macro exit +fn exit with int returns void then SYS_exit syscall1 drop -end +done diff --git a/include/linux.mcl b/include/linux.mcl index 5292b65..6b459b9 100644 --- a/include/linux.mcl +++ b/include/linux.mcl @@ -1,322 +1,322 @@ // file descriptors -macro STDIN 0 end -macro STDOUT 1 end -macro STDERR 2 end +const STDIN 0 end +const STDOUT 1 end +const STDERR 2 end // syscalls -macro SYS_read 0 end -macro SYS_write 1 end -macro SYS_open 2 end -macro SYS_close 3 end -macro SYS_stat 4 end -macro SYS_fstat 5 end -macro SYS_lstat 6 end -macro SYS_poll 7 end -macro SYS_lseek 8 end -macro SYS_mmap 9 end -macro SYS_mprotect 10 end -macro SYS_munmap 11 end -macro SYS_brk 12 end -macro SYS_rt_sigaction 13 end -macro SYS_rt_sigprocmask 14 end -macro SYS_rt_sigreturn 15 end -macro SYS_ioctl 16 end -macro SYS_pread64 17 end -macro SYS_pwrite64 18 end -macro SYS_readv 19 end -macro SYS_writev 20 end -macro SYS_access 21 end -macro SYS_pipe 22 end -macro SYS_select 23 end -macro SYS_sched_yield 24 end -macro SYS_mremap 25 end -macro SYS_msync 26 end -macro SYS_mincore 27 end -macro SYS_madvise 28 end -macro SYS_shmget 29 end -macro SYS_shmat 30 end -macro SYS_shmctl 31 end -macro SYS_dup 32 end -macro SYS_dup2 33 end -macro SYS_pause 34 end -macro SYS_nanosleep 35 end -macro SYS_getitimer 36 end -macro SYS_alarm 37 end -macro SYS_setitimer 38 end -macro SYS_getpid 39 end -macro SYS_sendfile 40 end -macro SYS_socket 41 end -macro SYS_connect 42 end -macro SYS_accept 43 end -macro SYS_sendto 44 end -macro SYS_recvfrom 45 end -macro SYS_sendmsg 46 end -macro SYS_recvmsg 47 end -macro SYS_shutdown 48 end -macro SYS_bind 49 end -macro SYS_listen 50 end -macro SYS_getsockname 51 end -macro SYS_getpeername 52 end -macro SYS_socketpair 53 end -macro SYS_setsockopt 54 end -macro SYS_getsockopt 55 end -macro SYS_clone 56 end -macro SYS_fork 57 end -macro SYS_vfork 58 end -macro SYS_execve 59 end -macro SYS_exit 60 end -macro SYS_wait4 61 end -macro SYS_kill 62 end -macro SYS_uname 63 end -macro SYS_semget 64 end -macro SYS_semop 65 end -macro SYS_semctl 66 end -macro SYS_shmdt 67 end -macro SYS_msgget 68 end -macro SYS_msgsnd 69 end -macro SYS_msgrcv 70 end -macro SYS_msgctl 71 end -macro SYS_fcntl 72 end -macro SYS_flock 73 end -macro SYS_fsync 74 end -macro SYS_fdatasync 75 end -macro SYS_truncate 76 end -macro SYS_ftruncate 77 end -macro SYS_getdents 78 end -macro SYS_getcwd 79 end -macro SYS_chdir 80 end -macro SYS_fchdir 81 end -macro SYS_rename 82 end -macro SYS_mkdir 83 end -macro SYS_rmdir 84 end -macro SYS_creat 85 end -macro SYS_link 86 end -macro SYS_unlink 87 end -macro SYS_symlink 88 end -macro SYS_readlink 89 end -macro SYS_chmod 90 end -macro SYS_fchmod 91 end -macro SYS_chown 92 end -macro SYS_fchown 93 end -macro SYS_lchown 94 end -macro SYS_umask 95 end -macro SYS_gettimeofday 96 end -macro SYS_getrlimit 97 end -macro SYS_getrusage 98 end -macro SYS_sysinfo 99 end -macro SYS_times 100 end -macro SYS_ptrace 101 end -macro SYS_getuid 102 end -macro SYS_syslog 103 end -macro SYS_getgid 104 end -macro SYS_setuid 105 end -macro SYS_setgid 106 end -macro SYS_geteuid 107 end -macro SYS_getegid 108 end -macro SYS_setpgid 109 end -macro SYS_getppid 110 end -macro SYS_getpgrp 111 end -macro SYS_setsid 112 end -macro SYS_setreuid 113 end -macro SYS_setregid 114 end -macro SYS_getgroups 115 end -macro SYS_setgroups 116 end -macro SYS_setresuid 117 end -macro SYS_getresuid 118 end -macro SYS_setresgid 119 end -macro SYS_getresgid 120 end -macro SYS_getpgid 121 end -macro SYS_setfsuid 122 end -macro SYS_setfsgid 123 end -macro SYS_getsid 124 end -macro SYS_capget 125 end -macro SYS_capset 126 end -macro SYS_rt_sigpending 127 end -macro SYS_rt_sigtimedwait 128 end -macro SYS_rt_sigqueueinfo 129 end -macro SYS_rt_sigsuspend 130 end -macro SYS_sigaltstack 131 end -macro SYS_utime 132 end -macro SYS_mknod 133 end -macro SYS_uselib 134 end -macro SYS_personality 135 end -macro SYS_ustat 136 end -macro SYS_statfs 137 end -macro SYS_fstatfs 138 end -macro SYS_sysfs 139 end -macro SYS_getpriority 140 end -macro SYS_setpriority 141 end -macro SYS_sched_setparam 142 end -macro SYS_sched_getparam 143 end -macro SYS_sched_setscheduler 144 end -macro SYS_sched_getscheduler 145 end -macro SYS_sched_get_priority_max 146 end -macro SYS_sched_get_priority_min 147 end -macro SYS_sched_rr_get_interval 148 end -macro SYS_mlock 149 end -macro SYS_munlock 150 end -macro SYS_mlockall 151 end -macro SYS_munlockall 152 end -macro SYS_vhangup 153 end -macro SYS_modify_ldt 154 end -macro SYS_pivot_root 155 end -macro SYS__sysctl 156 end -macro SYS_prctl 157 end -macro SYS_arch_prctl 158 end -macro SYS_adjtimex 159 end -macro SYS_setrlimit 160 end -macro SYS_chroot 161 end -macro SYS_sync 162 end -macro SYS_acct 163 end -macro SYS_settimeofday 164 end -macro SYS_mount 165 end -macro SYS_umount2 166 end -macro SYS_swapon 167 end -macro SYS_swapoff 168 end -macro SYS_reboot 169 end -macro SYS_sethostname 170 end -macro SYS_setdomainname 171 end -macro SYS_iopl 172 end -macro SYS_ioperm 173 end -macro SYS_create_module 174 end -macro SYS_init_module 175 end -macro SYS_delete_module 176 end -macro SYS_get_kernel_syms 177 end -macro SYS_query_module 178 end -macro SYS_quotactl 179 end -macro SYS_nfsservctl 180 end -macro SYS_getpmsg 181 end -macro SYS_putpmsg 182 end -macro SYS_afs_syscall 183 end -macro SYS_tuxcall 184 end -macro SYS_security 185 end -macro SYS_gettid 186 end -macro SYS_readahead 187 end -macro SYS_setxattr 188 end -macro SYS_lsetxattr 189 end -macro SYS_fsetxattr 190 end -macro SYS_getxattr 191 end -macro SYS_lgetxattr 192 end -macro SYS_fgetxattr 193 end -macro SYS_listxattr 194 end -macro SYS_llistxattr 195 end -macro SYS_flistxattr 196 end -macro SYS_removexattr 197 end -macro SYS_lremovexattr 198 end -macro SYS_fremovexattr 199 end -macro SYS_tkill 200 end -macro SYS_time 201 end -macro SYS_futex 202 end -macro SYS_sched_setaffinity 203 end -macro SYS_sched_getaffinity 204 end -macro SYS_set_thread_area 205 end -macro SYS_io_setup 206 end -macro SYS_io_destroy 207 end -macro SYS_io_getevents 208 end -macro SYS_io_submit 209 end -macro SYS_io_cancel 210 end -macro SYS_get_thread_area 211 end -macro SYS_lookup_dcookie 212 end -macro SYS_epoll_create 213 end -macro SYS_epoll_ctl_old 214 end -macro SYS_epoll_wait_old 215 end -macro SYS_remap_file_pages 216 end -macro SYS_getdents64 217 end -macro SYS_set_tid_address 218 end -macro SYS_restart_syscall 219 end -macro SYS_semtimedop 220 end -macro SYS_fadvise64 221 end -macro SYS_timer_create 222 end -macro SYS_timer_settime 223 end -macro SYS_timer_gettime 224 end -macro SYS_timer_getoverrun 225 end -macro SYS_timer_delete 226 end -macro SYS_clock_settime 227 end -macro SYS_clock_gettime 228 end -macro SYS_clock_getres 229 end -macro SYS_clock_nanosleep 230 end -macro SYS_exit_group 231 end -macro SYS_epoll_wait 232 end -macro SYS_epoll_ctl 233 end -macro SYS_tgkill 234 end -macro SYS_utimes 235 end -macro SYS_vserver 236 end -macro SYS_mbind 237 end -macro SYS_set_mempolicy 238 end -macro SYS_get_mempolicy 239 end -macro SYS_mq_open 240 end -macro SYS_mq_unlink 241 end -macro SYS_mq_timedsend 242 end -macro SYS_mq_timedreceive 243 end -macro SYS_mq_notify 244 end -macro SYS_mq_getsetattr 245 end -macro SYS_kexec_load 246 end -macro SYS_waitid 247 end -macro SYS_add_key 248 end -macro SYS_request_key 249 end -macro SYS_keyctl 250 end -macro SYS_ioprio_set 251 end -macro SYS_ioprio_get 252 end -macro SYS_inotify_init 253 end -macro SYS_inotify_add_watch 254 end -macro SYS_inotify_rm_watch 255 end -macro SYS_migrate_pages 256 end -macro SYS_openat 257 end -macro SYS_mkdirat 258 end -macro SYS_mknodat 259 end -macro SYS_fchownat 260 end -macro SYS_futimesat 261 end -macro SYS_newfstatat 262 end -macro SYS_unlinkat 263 end -macro SYS_renameat 264 end -macro SYS_linkat 265 end -macro SYS_symlinkat 266 end -macro SYS_readlinkat 267 end -macro SYS_fchmodat 268 end -macro SYS_faccessat 269 end -macro SYS_pselect6 270 end -macro SYS_ppoll 271 end -macro SYS_unshare 272 end -macro SYS_set_robust_list 273 end -macro SYS_get_robust_list 274 end -macro SYS_splice 275 end -macro SYS_tee 276 end -macro SYS_sync_file_range 277 end -macro SYS_vmsplice 278 end -macro SYS_move_pages 279 end -macro SYS_utimensat 280 end -macro SYS_epoll_pwait 281 end -macro SYS_signalfd 282 end -macro SYS_timerfd_create 283 end -macro SYS_eventfd 284 end -macro SYS_fallocate 285 end -macro SYS_timerfd_settime 286 end -macro SYS_timerfd_gettime 287 end -macro SYS_accept4 288 end -macro SYS_signalfd4 289 end -macro SYS_eventfd2 290 end -macro SYS_epoll_create1 291 end -macro SYS_dup3 292 end -macro SYS_pipe2 293 end -macro SYS_inotify_init1 294 end -macro SYS_preadv 295 end -macro SYS_pwritev 296 end -macro SYS_rt_tgsigqueueinfo 297 end -macro SYS_perf_event_open 298 end -macro SYS_recvmmsg 299 end -macro SYS_fanotify_init 300 end -macro SYS_fanotify_mark 301 end -macro SYS_prlimit64 302 end -macro SYS_name_to_handle_at 303 end -macro SYS_open_by_handle_at 304 end -macro SYS_clock_adjtime 305 end -macro SYS_syncfs 306 end -macro SYS_sendmmsg 307 end -macro SYS_setns 308 end -macro SYS_getcpu 309 end -macro SYS_process_vm_readv 310 end -macro SYS_process_vm_writev 311 end -macro SYS_kcmp 312 end -macro SYS_finit_module 313 end \ No newline at end of file +const SYS_read 0 end +const SYS_write 1 end +const SYS_open 2 end +const SYS_close 3 end +const SYS_stat 4 end +const SYS_fstat 5 end +const SYS_lstat 6 end +const SYS_poll 7 end +const SYS_lseek 8 end +const SYS_mmap 9 end +const SYS_mprotect 10 end +const SYS_munmap 11 end +const SYS_brk 12 end +const SYS_rt_sigaction 13 end +const SYS_rt_sigprocmask 14 end +const SYS_rt_sigreturn 15 end +const SYS_ioctl 16 end +const SYS_pread64 17 end +const SYS_pwrite64 18 end +const SYS_readv 19 end +const SYS_writev 20 end +const SYS_access 21 end +const SYS_pipe 22 end +const SYS_select 23 end +const SYS_sched_yield 24 end +const SYS_mremap 25 end +const SYS_msync 26 end +const SYS_mincore 27 end +const SYS_madvise 28 end +const SYS_shmget 29 end +const SYS_shmat 30 end +const SYS_shmctl 31 end +const SYS_dup 32 end +const SYS_dup2 33 end +const SYS_pause 34 end +const SYS_nanosleep 35 end +const SYS_getitimer 36 end +const SYS_alarm 37 end +const SYS_setitimer 38 end +const SYS_getpid 39 end +const SYS_sendfile 40 end +const SYS_socket 41 end +const SYS_connect 42 end +const SYS_accept 43 end +const SYS_sendto 44 end +const SYS_recvfrom 45 end +const SYS_sendmsg 46 end +const SYS_recvmsg 47 end +const SYS_shutdown 48 end +const SYS_bind 49 end +const SYS_listen 50 end +const SYS_getsockname 51 end +const SYS_getpeername 52 end +const SYS_socketpair 53 end +const SYS_setsockopt 54 end +const SYS_getsockopt 55 end +const SYS_clone 56 end +const SYS_fork 57 end +const SYS_vfork 58 end +const SYS_execve 59 end +const SYS_exit 60 end +const SYS_wait4 61 end +const SYS_kill 62 end +const SYS_uname 63 end +const SYS_semget 64 end +const SYS_semop 65 end +const SYS_semctl 66 end +const SYS_shmdt 67 end +const SYS_msgget 68 end +const SYS_msgsnd 69 end +const SYS_msgrcv 70 end +const SYS_msgctl 71 end +const SYS_fcntl 72 end +const SYS_flock 73 end +const SYS_fsync 74 end +const SYS_fdatasync 75 end +const SYS_truncate 76 end +const SYS_ftruncate 77 end +const SYS_getdents 78 end +const SYS_getcwd 79 end +const SYS_chdir 80 end +const SYS_fchdir 81 end +const SYS_rename 82 end +const SYS_mkdir 83 end +const SYS_rmdir 84 end +const SYS_creat 85 end +const SYS_link 86 end +const SYS_unlink 87 end +const SYS_symlink 88 end +const SYS_readlink 89 end +const SYS_chmod 90 end +const SYS_fchmod 91 end +const SYS_chown 92 end +const SYS_fchown 93 end +const SYS_lchown 94 end +const SYS_umask 95 end +const SYS_gettimeofday 96 end +const SYS_getrlimit 97 end +const SYS_getrusage 98 end +const SYS_sysinfo 99 end +const SYS_times 100 end +const SYS_ptrace 101 end +const SYS_getuid 102 end +const SYS_syslog 103 end +const SYS_getgid 104 end +const SYS_setuid 105 end +const SYS_setgid 106 end +const SYS_geteuid 107 end +const SYS_getegid 108 end +const SYS_setpgid 109 end +const SYS_getppid 110 end +const SYS_getpgrp 111 end +const SYS_setsid 112 end +const SYS_setreuid 113 end +const SYS_setregid 114 end +const SYS_getgroups 115 end +const SYS_setgroups 116 end +const SYS_setresuid 117 end +const SYS_getresuid 118 end +const SYS_setresgid 119 end +const SYS_getresgid 120 end +const SYS_getpgid 121 end +const SYS_setfsuid 122 end +const SYS_setfsgid 123 end +const SYS_getsid 124 end +const SYS_capget 125 end +const SYS_capset 126 end +const SYS_rt_sigpending 127 end +const SYS_rt_sigtimedwait 128 end +const SYS_rt_sigqueueinfo 129 end +const SYS_rt_sigsuspend 130 end +const SYS_sigaltstack 131 end +const SYS_utime 132 end +const SYS_mknod 133 end +const SYS_uselib 134 end +const SYS_personality 135 end +const SYS_ustat 136 end +const SYS_statfs 137 end +const SYS_fstatfs 138 end +const SYS_sysfs 139 end +const SYS_getpriority 140 end +const SYS_setpriority 141 end +const SYS_sched_setparam 142 end +const SYS_sched_getparam 143 end +const SYS_sched_setscheduler 144 end +const SYS_sched_getscheduler 145 end +const SYS_sched_get_priority_max 146 end +const SYS_sched_get_priority_min 147 end +const SYS_sched_rr_get_interval 148 end +const SYS_mlock 149 end +const SYS_munlock 150 end +const SYS_mlockall 151 end +const SYS_munlockall 152 end +const SYS_vhangup 153 end +const SYS_modify_ldt 154 end +const SYS_pivot_root 155 end +const SYS__sysctl 156 end +const SYS_prctl 157 end +const SYS_arch_prctl 158 end +const SYS_adjtimex 159 end +const SYS_setrlimit 160 end +const SYS_chroot 161 end +const SYS_sync 162 end +const SYS_acct 163 end +const SYS_settimeofday 164 end +const SYS_mount 165 end +const SYS_umount2 166 end +const SYS_swapon 167 end +const SYS_swapoff 168 end +const SYS_reboot 169 end +const SYS_sethostname 170 end +const SYS_setdomainname 171 end +const SYS_iopl 172 end +const SYS_ioperm 173 end +const SYS_create_module 174 end +const SYS_init_module 175 end +const SYS_delete_module 176 end +const SYS_get_kernel_syms 177 end +const SYS_query_module 178 end +const SYS_quotactl 179 end +const SYS_nfsservctl 180 end +const SYS_getpmsg 181 end +const SYS_putpmsg 182 end +const SYS_afs_syscall 183 end +const SYS_tuxcall 184 end +const SYS_security 185 end +const SYS_gettid 186 end +const SYS_readahead 187 end +const SYS_setxattr 188 end +const SYS_lsetxattr 189 end +const SYS_fsetxattr 190 end +const SYS_getxattr 191 end +const SYS_lgetxattr 192 end +const SYS_fgetxattr 193 end +const SYS_listxattr 194 end +const SYS_llistxattr 195 end +const SYS_flistxattr 196 end +const SYS_removexattr 197 end +const SYS_lremovexattr 198 end +const SYS_fremovexattr 199 end +const SYS_tkill 200 end +const SYS_time 201 end +const SYS_futex 202 end +const SYS_sched_setaffinity 203 end +const SYS_sched_getaffinity 204 end +const SYS_set_thread_area 205 end +const SYS_io_setup 206 end +const SYS_io_destroy 207 end +const SYS_io_getevents 208 end +const SYS_io_submit 209 end +const SYS_io_cancel 210 end +const SYS_get_thread_area 211 end +const SYS_lookup_dcookie 212 end +const SYS_epoll_create 213 end +const SYS_epoll_ctl_old 214 end +const SYS_epoll_wait_old 215 end +const SYS_remap_file_pages 216 end +const SYS_getdents64 217 end +const SYS_set_tid_address 218 end +const SYS_restart_syscall 219 end +const SYS_semtimedop 220 end +const SYS_fadvise64 221 end +const SYS_timer_create 222 end +const SYS_timer_settime 223 end +const SYS_timer_gettime 224 end +const SYS_timer_getoverrun 225 end +const SYS_timer_delete 226 end +const SYS_clock_settime 227 end +const SYS_clock_gettime 228 end +const SYS_clock_getres 229 end +const SYS_clock_nanosleep 230 end +const SYS_exit_group 231 end +const SYS_epoll_wait 232 end +const SYS_epoll_ctl 233 end +const SYS_tgkill 234 end +const SYS_utimes 235 end +const SYS_vserver 236 end +const SYS_mbind 237 end +const SYS_set_mempolicy 238 end +const SYS_get_mempolicy 239 end +const SYS_mq_open 240 end +const SYS_mq_unlink 241 end +const SYS_mq_timedsend 242 end +const SYS_mq_timedreceive 243 end +const SYS_mq_notify 244 end +const SYS_mq_getsetattr 245 end +const SYS_kexec_load 246 end +const SYS_waitid 247 end +const SYS_add_key 248 end +const SYS_request_key 249 end +const SYS_keyctl 250 end +const SYS_ioprio_set 251 end +const SYS_ioprio_get 252 end +const SYS_inotify_init 253 end +const SYS_inotify_add_watch 254 end +const SYS_inotify_rm_watch 255 end +const SYS_migrate_pages 256 end +const SYS_openat 257 end +const SYS_mkdirat 258 end +const SYS_mknodat 259 end +const SYS_fchownat 260 end +const SYS_futimesat 261 end +const SYS_newfstatat 262 end +const SYS_unlinkat 263 end +const SYS_renameat 264 end +const SYS_linkat 265 end +const SYS_symlinkat 266 end +const SYS_readlinkat 267 end +const SYS_fchmodat 268 end +const SYS_faccessat 269 end +const SYS_pselect6 270 end +const SYS_ppoll 271 end +const SYS_unshare 272 end +const SYS_set_robust_list 273 end +const SYS_get_robust_list 274 end +const SYS_splice 275 end +const SYS_tee 276 end +const SYS_sync_file_range 277 end +const SYS_vmsplice 278 end +const SYS_move_pages 279 end +const SYS_utimensat 280 end +const SYS_epoll_pwait 281 end +const SYS_signalfd 282 end +const SYS_timerfd_create 283 end +const SYS_eventfd 284 end +const SYS_fallocate 285 end +const SYS_timerfd_settime 286 end +const SYS_timerfd_gettime 287 end +const SYS_accept4 288 end +const SYS_signalfd4 289 end +const SYS_eventfd2 290 end +const SYS_epoll_create1 291 end +const SYS_dup3 292 end +const SYS_pipe2 293 end +const SYS_inotify_init1 294 end +const SYS_preadv 295 end +const SYS_pwritev 296 end +const SYS_rt_tgsigqueueinfo 297 end +const SYS_perf_event_open 298 end +const SYS_recvmmsg 299 end +const SYS_fanotify_init 300 end +const SYS_fanotify_mark 301 end +const SYS_prlimit64 302 end +const SYS_name_to_handle_at 303 end +const SYS_open_by_handle_at 304 end +const SYS_clock_adjtime 305 end +const SYS_syncfs 306 end +const SYS_sendmmsg 307 end +const SYS_setns 308 end +const SYS_getcpu 309 end +const SYS_process_vm_readv 310 end +const SYS_process_vm_writev 311 end +const SYS_kcmp 312 end +const SYS_finit_module 313 end \ No newline at end of file diff --git a/include/mem.mcl b/include/mem.mcl index 2f1ae8e..e69de29 100644 --- a/include/mem.mcl +++ b/include/mem.mcl @@ -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 - diff --git a/include/std.mcl b/include/std.mcl index 78fcb01..e4e2146 100644 --- a/include/std.mcl +++ b/include/std.mcl @@ -2,4 +2,5 @@ include "linux.mcl" include "io.mcl" include "util.mcl" include "int.mcl" -include "fs.mcl" \ No newline at end of file +include "fs.mcl" +include "compat.mcl" \ No newline at end of file diff --git a/include/util.mcl b/include/util.mcl index 605bc8b..0044e8a 100644 --- a/include/util.mcl +++ b/include/util.mcl @@ -5,11 +5,11 @@ // @arg str_len: Int // @arg str_ptr: Ptr // @ret NULL/NEVER -macro assert +fn assert with bool int ptr returns void then rot if else "Assert failed: \"" eputs eputs "\". Exiting!\n" eputs 1 exit end -end \ No newline at end of file +done \ No newline at end of file diff --git a/src/compile/linux_x86_64.rs b/src/compile/linux_x86_64.rs index 098d1b5..a87969e 100644 --- a/src/compile/linux_x86_64.rs +++ b/src/compile/linux_x86_64.rs @@ -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 color_eyre::Result; use crate::compile::commands::linux_x86_64_compile_and_link; 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{ + let debug = args.get_opt_level()? < 1; + 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 of_o = PathBuf::from("/tmp/mclang_comp.o"); @@ -22,18 +25,19 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ of_o.set_extension("o"); of_a.set_extension("nasm"); - let file = fs::File::create(&of_a)?; let mut writer = BufWriter::new(&file); - let mut memories: Vec<(usize, usize)> = Vec::new(); + let mut memories: Vec = Vec::new(); + let mut constants: HashMap = HashMap::new(); + let mut functions: Vec = Vec::new(); // println!("{}", tokens.len()); let mut strings: Vec = Vec::new(); - + writeln!(writer, "BITS 64")?; writeln!(writer, "segment .text")?; - writeln!(writer, "print:")?; + writeln!(writer, "_dbg_print:")?; writeln!(writer, " mov r9, -3689348814741910323")?; writeln!(writer, " sub rsp, 40")?; writeln!(writer, " mov BYTE [rsp+31], 10")?; @@ -68,46 +72,76 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ writeln!(writer, " ret")?; 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; while ti < tokens.len() { 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() { // stack OpType::Instruction(instruction) => { match instruction { InstructionType::PushInt => { - writeln!(writer, " ;; -- push int {}", token.value)?; writeln!(writer, " mov rax, {}", token.value)?; writeln!(writer, " push rax")?; ti += 1; }, InstructionType::PushStr => { - writeln!(writer, " ;; -- push str \"{}\"", token.text.escape_default())?; writeln!(writer, " mov rax, {}", token.text.len())?; 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()); ti += 1; } InstructionType::Drop => { - writeln!(writer, " ;; -- drop")?; writeln!(writer, " pop rax")?; ti += 1; }, InstructionType::Print => { - writeln!(writer, " ;; -- print")?; writeln!(writer, " pop rdi")?; - writeln!(writer, " call print")?; + writeln!(writer, " call _dbg_print")?; ti += 1; }, InstructionType::Dup => { - writeln!(writer, " ;; -- dup")?; writeln!(writer, " pop rax")?; writeln!(writer, " push rax")?; writeln!(writer, " push rax")?; @@ -116,7 +150,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ }, InstructionType::Rot => { - writeln!(writer, " ;; -- rot")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; writeln!(writer, " pop rcx")?; @@ -127,7 +160,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Swap => { - writeln!(writer, " ;; -- swap")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; writeln!(writer, " push rax")?; @@ -136,7 +168,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Over => { - writeln!(writer, " ;; -- over")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; writeln!(writer, " push rbx")?; @@ -145,33 +176,51 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, - - //mem - InstructionType::Mem => { - writeln!(writer, " ;; -- mem")?; - writeln!(writer, " push mem")?; - ti += 1; - } InstructionType::Load8 => { - writeln!(writer, " ;; -- load")?; writeln!(writer, " pop rax")?; writeln!(writer, " xor rbx, rbx")?; - writeln!(writer, " mov bl, [rax]")?; + writeln!(writer, " mov bl, byte [rax]")?; writeln!(writer, " push rbx")?; ti += 1; } InstructionType::Store8 => { - writeln!(writer, " ;; -- store")?; writeln!(writer, " pop rbx")?; 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; } // math InstructionType::Plus => { - writeln!(writer, " ;; -- plus")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; writeln!(writer, " add rax, rbx")?; @@ -179,7 +228,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Minus => { - writeln!(writer, " ;; -- minus")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; writeln!(writer, " sub rbx, rax")?; @@ -187,7 +235,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Equals => { - writeln!(writer, " ;; -- equals")?; writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rdx, 1")?; writeln!(writer, " pop rax")?; @@ -198,7 +245,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Lt => { - writeln!(writer, " ;; -- lt")?; writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rdx, 1")?; writeln!(writer, " pop rbx")?; @@ -209,7 +255,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Gt => { - writeln!(writer, " ;; -- gt")?; writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rdx, 1")?; writeln!(writer, " pop rbx")?; @@ -220,7 +265,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::NotEquals => { - writeln!(writer, " ;; -- not equals")?; writeln!(writer, " mov rcx, 1")?; writeln!(writer, " mov rdx, 0")?; writeln!(writer, " pop rax")?; @@ -231,7 +275,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Le => { - writeln!(writer, " ;; -- lt")?; writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rdx, 1")?; writeln!(writer, " pop rbx")?; @@ -242,7 +285,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Ge => { - writeln!(writer, " ;; -- gt")?; writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rdx, 1")?; writeln!(writer, " pop rbx")?; @@ -253,7 +295,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Band => { - writeln!(writer, " ;; -- band")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; writeln!(writer, " and rbx, rax")?; @@ -261,7 +302,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Bor => { - writeln!(writer, " ;; -- bor")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; writeln!(writer, " or rbx, rax")?; @@ -269,7 +309,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Shr => { - writeln!(writer, " ;; -- shr")?; writeln!(writer, " pop rcx")?; writeln!(writer, " pop rbx")?; writeln!(writer, " shr rbx, cl")?; @@ -277,7 +316,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Shl => { - writeln!(writer, " ;; -- shl")?; writeln!(writer, " pop rcx")?; writeln!(writer, " pop rbx")?; writeln!(writer, " shl rbx, cl")?; @@ -285,7 +323,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::DivMod => { - writeln!(writer, " ;; -- div")?; writeln!(writer, " xor rdx, rdx")?; writeln!(writer, " pop rbx")?; writeln!(writer, " pop rax")?; @@ -295,7 +332,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Mul => { - writeln!(writer, " ;; -- mul")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; writeln!(writer, " mul rbx")?; @@ -303,14 +339,12 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Syscall0 => { - writeln!(writer, " ;; -- syscall0")?; writeln!(writer, " pop rax")?; writeln!(writer, " syscall")?; writeln!(writer, " push rax")?; ti += 1; }, InstructionType::Syscall1 => { - writeln!(writer, " ;; -- syscall1")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; writeln!(writer, " syscall")?; @@ -318,7 +352,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Syscall2 => { - writeln!(writer, " ;; -- syscall2")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; writeln!(writer, " pop rsi")?; @@ -327,7 +360,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Syscall3 => { - writeln!(writer, " ;; -- syscall3")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; writeln!(writer, " pop rsi")?; @@ -338,7 +370,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Syscall4 => { - writeln!(writer, " ;; -- syscall4")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; writeln!(writer, " pop rsi")?; @@ -349,7 +380,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Syscall5 => { - writeln!(writer, " ;; -- syscall5")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; writeln!(writer, " pop rsi")?; @@ -361,7 +391,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Syscall6 => { - writeln!(writer, " ;; -- syscall6")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; writeln!(writer, " pop rsi")?; @@ -374,14 +403,48 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::MemUse => { - writeln!(writer, " ;; -- MemUse")?; writeln!(writer, " push mem_{}", token.addr.unwrap())?; ti += 1; }, - InstructionType::None => unreachable!(), - InstructionType::CastBool => ti += 1, - InstructionType::CastPtr => ti += 1, - InstructionType::CastInt => ti += 1, + InstructionType::None => { + println!("{token:?}"); + unreachable!() + }, + 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{ match keyword { // block - KeywordType::If => { - writeln!(writer, " ;; -- if")?; + KeywordType::If | + KeywordType::Do => { writeln!(writer, " pop rax")?; writeln!(writer, " test rax, rax")?; writeln!(writer, " jz addr_{}", token.jmp)?; ti += 1; - }, + } KeywordType::Else => { - writeln!(writer, " ;; -- else")?; writeln!(writer, " jmp addr_{}", token.jmp)?; ti += 1; }, 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; } KeywordType::End => { - writeln!(writer, " ;; -- end")?; if ti + 1 != token.jmp { - writeln!(writer, " jmp addr_{}", token.jmp)?; + // writeln!(writer, " jmp addr_{}", token.jmp)?; } ti += 1; }, 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; } - KeywordType::Macro | - KeywordType::Include - => unreachable!() + KeywordType::ConstantDef => { + // TODO: after we add c style strings add supoort for them in constants + 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, "end:")?; writeln!(writer, " mov rax, 60")?; writeln!(writer, " mov rdi, 0")?; writeln!(writer, " syscall")?; @@ -442,18 +526,65 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ writeln!(writer, " str_{}: db {} ; {}", i, s_list, s.escape_default())?; } - writeln!(writer, "segment .bss")?; - for (_, s) in memories.iter().enumerate() { - writeln!(writer, " mem_{}: resb {}", s.0, s.1)?; + for (_, c) in constants { + if !c.used { + 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()?; + + + 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)?; if args.run { let c = linux_x86_64_run(&of_c, &[], args.quiet)?; return Ok(c); } + Ok(0) +} + + +fn pre_compile_steps(_code: &str, functions: Vec) -> 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(()) } \ No newline at end of file diff --git a/src/compile/mod.rs b/src/compile/mod.rs index 9c22480..8391aa0 100644 --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -1,5 +1,27 @@ +use crate::constants::Loc; + pub mod linux_x86_64; pub mod commands; -pub const MEM_SZ: usize = 640 * 1000; // 4kb -pub const STRING_SZ: usize = 640 * 1000; // 4kb +#[derive(Debug, Clone)] +pub struct Constant { + pub loc: Loc, + pub name: String, + pub value_i: Option, + pub value_s: Option, + 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 +} \ No newline at end of file diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..55ff8b4 --- /dev/null +++ b/src/config.rs @@ -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 \ No newline at end of file diff --git a/src/constants.rs b/src/constants.rs index 99111d5..ea7d9e2 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,5 +1,4 @@ -pub const ALLOW_MACRO_REDEFINITION: bool = true; #[derive(Debug, Clone, PartialEq)] @@ -33,9 +32,12 @@ pub enum InstructionType { // mem - Mem, Load8, Store8, + Load32, + Store32, + Load64, + Store64, // syscalls Syscall0, @@ -49,21 +51,41 @@ pub enum InstructionType { CastBool, CastPtr, CastInt, + CastVoid, + // typing + TypeBool, + TypePtr, + TypeInt, + TypeVoid, + TypeStr, + TypeAny, + Returns, + With, + + FnCall, MemUse, + ConstUse, + + Return, None // Used for macros and any other non built in word definitions } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum KeywordType { If, Else, End, While, Do, - Macro, Include, - Memory + Memory, + Constant, + ConstantDef, + Function, + FunctionDef, + FunctionThen, + FunctionDone } #[derive(Debug, Clone, PartialEq)] @@ -75,6 +97,7 @@ pub enum OpType { #[derive(Debug, Clone)] pub struct Operator{ pub typ: OpType, + pub tok_typ: TokenType, pub value: usize, pub text: String, //? only used for OpType::PushStr pub addr: Option, //? only used for OpType::PushStr @@ -83,14 +106,15 @@ pub struct 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 { typ, value, jmp: 0, addr: None, text, - loc: (file, row, col) + loc: (file, row, col), + tok_typ, } } pub fn set_addr(mut self, addr: usize) -> Self { @@ -108,7 +132,7 @@ impl OpType { InstructionType::PushInt => "Number", InstructionType::PushStr => "String", - InstructionType::Print => "print", + InstructionType::Print => "_dbg_print", InstructionType::Dup => "dup", InstructionType::Drop => "drop", InstructionType::Rot => "rot", @@ -128,9 +152,12 @@ impl OpType { InstructionType::Shl => "shl", InstructionType::DivMod => "divmod", InstructionType::Mul => "*", - InstructionType::Mem => "mem", - InstructionType::Load8 => "!8", - InstructionType::Store8 => "@8", + InstructionType::Load8 => "load8", + InstructionType::Store8 => "store8", + InstructionType::Load32 => "load32", + InstructionType::Store32 => "store32", + InstructionType::Load64 => "load64", + InstructionType::Store64 => "store64", InstructionType::Syscall0 => "syscall0", InstructionType::Syscall1 => "syscall1", InstructionType::Syscall2 => "syscall2", @@ -141,8 +168,20 @@ impl OpType { InstructionType::CastBool => "cast(bool", InstructionType::CastPtr => "cast(ptr)", InstructionType::CastInt => "cast(int)", - InstructionType::MemUse => "MemUse", + InstructionType::CastVoid => "cast(void)", 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) => { @@ -152,9 +191,14 @@ impl OpType { KeywordType::End => "end", KeywordType::While => "while", KeywordType::Do => "do", - KeywordType::Macro => "macro", 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 value: Option, //* only used for Memories pub addr: Option, //* 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)] @@ -210,6 +254,8 @@ pub enum Types { Bool, Ptr, Int, + Void, + Str, Any // U8, // U16, diff --git a/src/errors/mod.rs b/src/errors/mod.rs new file mode 100644 index 0000000..d6e14c3 --- /dev/null +++ b/src/errors/mod.rs @@ -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" + ) + ) + ); +} \ No newline at end of file diff --git a/src/interpret/linux_x86_64/mod.rs b/src/interpret/linux_x86_64/mod.rs index 31b10ac..7ed383f 100644 --- a/src/interpret/linux_x86_64/mod.rs +++ b/src/interpret/linux_x86_64/mod.rs @@ -1,9 +1,11 @@ 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 color_eyre::Result; use eyre::eyre; + +use super::{Memory, Function, Constant}; mod syscalls; fn stack_pop(stack: &mut Vec, pos: &Loc) -> Result { @@ -13,56 +15,66 @@ fn stack_pop(stack: &mut Vec, pos: &Loc) -> Result { } } -pub fn run(tokens: &[crate::constants::Operator]) -> Result{ +pub fn run(ops: &[crate::constants::Operator]) -> Result{ let mut stack: Vec = Vec::new(); - let mut ti = 0; - let mut mem: Vec = vec![0; crate::compile::MEM_SZ + crate::compile::STRING_SZ]; + let mut mem: Vec = vec![0; crate::MEM_SZ + crate::STRING_SZ]; 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 = HashMap::new(); + let mut ret_stack: Vec = Vec::new(); + // for token in &tokens { // println!("{{typ: \"{:?}\", val: {}, jmp: {}}}", token.typ, token.value, token.jmp); - // } - while ti < tokens.len() { - let token = &tokens[ti]; - let pos = token.loc.clone(); - // println!("{:?}", token.typ); - match token.typ.clone() { + + // jump to main func + let mut ip = if let Some(i) = functions.get("main") {i.id} else { + crate::errors::missing_main_fn(); + return Err(eyre!("")); + }; + + while ip < ops.len() { + let op = &ops[ip]; + let pos = op.loc.clone(); + match op.typ.clone() { OpType::Instruction(instruction) => { match instruction { InstructionType::PushInt => { - stack.push(token.value); - ti += 1; + stack.push(op.value); + ip += 1; }, InstructionType::PushStr => { - if token.addr.is_none() { - stack.push(token.text.len()); // string len - stack.push(string_idx + crate::compile::MEM_SZ); + if op.addr.is_none() { + stack.push(op.text.len()); // string len + stack.push(string_idx + crate::MEM_SZ); - for c in token.text.bytes() { - mem[crate::compile::MEM_SZ + string_idx] = c; + for c in op.text.bytes() { + mem[crate::MEM_SZ + string_idx] = u64::from(c); string_idx += 1; } } else { - stack.push(token.text.len()); - if let Some(addr) = token.addr { + stack.push(op.text.len()); + if let Some(addr) = op.addr { stack.push(addr); } } - ti += 1; + ip += 1; }, InstructionType::Drop => { stack.pop(); - ti += 1; + ip += 1; }, InstructionType::Dup => { let a = stack_pop(&mut stack, &pos)?; stack.push(a); stack.push(a); - ti += 1; + ip += 1; }, InstructionType::Rot => { @@ -72,14 +84,14 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result{ stack.push(b); stack.push(a); stack.push(c); - ti += 1; + ip += 1; } InstructionType::Swap => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(a); stack.push(b); - ti += 1; + ip += 1; } InstructionType::Over => { let a = stack_pop(&mut stack, &pos)?; @@ -87,43 +99,67 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result{ stack.push(b); stack.push(a); stack.push(b); - ti += 1; + ip += 1; } InstructionType::Print => { let a = stack_pop(&mut stack, &pos)?; println!("{a}"); // let _ = io::stdout().flush(); - ti += 1; + ip += 1; }, - // mem - - InstructionType::Mem => { - stack.push(0); - ti += 1; - } - InstructionType::Load8 => { + #[allow(clippy::cast_possible_truncation)] + InstructionType::Load8 | + InstructionType::Load32 | + InstructionType::Load64 => { let a = stack_pop(&mut stack, &pos)?; - if a > crate::compile::MEM_SZ { - lerror!(&token.loc, "Invalid memory address {a}"); + if a > crate::MEM_SZ { + lerror!(&op.loc, "Invalid memory address {a}"); return Ok(1); } let byte = mem[a]; stack.push(byte as usize); - ti += 1; + ip += 1; } #[allow(clippy::cast_possible_truncation)] InstructionType::Store8 => { let val = stack_pop(&mut stack, &pos)?; let addr = stack_pop(&mut stack, &pos)?; - if addr > crate::compile::MEM_SZ { - lerror!(&token.loc, "Invalid memory address {addr}"); + if addr > crate::MEM_SZ { + lerror!(&op.loc, "Invalid memory address {addr}"); return Ok(1); } - mem[addr] = (val & 0xFF) as u8; - ti += 1; + mem[addr] = u64::from(val as u8); + 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 @@ -131,77 +167,77 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result{ let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(b + a); - ti += 1; + ip += 1; }, InstructionType::Minus => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(b - a); - ti += 1; + ip += 1; }, InstructionType::Equals => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(usize::from(b == a)); - ti += 1; + ip += 1; }, InstructionType::Gt => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(usize::from(b > a)); - ti += 1; + ip += 1; }, InstructionType::Lt => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(usize::from(b < a)); - ti += 1; + ip += 1; }, InstructionType::NotEquals => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(usize::from(b != a)); - ti += 1; + ip += 1; }, InstructionType::Ge => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(usize::from(b >= a)); - ti += 1; + ip += 1; }, InstructionType::Le => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(usize::from(b <= a)); - ti += 1; + ip += 1; }, InstructionType::Band => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(a & b); - ti += 1; + ip += 1; } InstructionType::Bor => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(a | b); - ti += 1; + ip += 1; } InstructionType::Shr => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(b >> a); - ti += 1; + ip += 1; } InstructionType::Shl => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(b << a); - ti += 1; + ip += 1; } InstructionType::DivMod => { @@ -209,13 +245,13 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result{ let b = stack_pop(&mut stack, &pos)?; stack.push(b / a); stack.push(b % a); - ti += 1; + ip += 1; } InstructionType::Mul => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(b * a); - ti += 1; + ip += 1; } InstructionType::Syscall0 => { todo!(); @@ -245,7 +281,7 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result{ }; stack.push(ret); // println!("{}", stack.len()); - ti += 1; + ip += 1; }, InstructionType::Syscall4 => { todo!(); @@ -261,13 +297,41 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result{ }, InstructionType::MemUse => { - let m = memories.get(&token.addr.unwrap()).unwrap(); - stack.push(*m); - ti += 1; + let m = memories.get(&op.addr.unwrap()).unwrap(); + stack.push(m.id); + ip += 1; }, - InstructionType::CastBool => ti += 1, - InstructionType::CastPtr => ti += 1, - InstructionType::CastInt => ti += 1, + InstructionType::FnCall => { + ret_stack.push(ip); + 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!(), } @@ -279,30 +343,42 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result{ let a = stack_pop(&mut stack, &pos)?; if a == 0 { // println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp); - ti = token.jmp; + ip = op.jmp; } else { - ti += 1; + ip += 1; } }, KeywordType::Else | KeywordType::End => { - ti = token.jmp; - } - KeywordType::While => { - ti += 1; + ip = op.jmp; } KeywordType::Do => { let a = stack.pop().unwrap(); if a == 0 { - ti = token.jmp; + ip = op.jmp; } else { - ti += 1; + ip += 1; } } - KeywordType::Memory => { - memories.insert(token.addr.unwrap(), token.value); - ti += 1; + KeywordType::While | //* exept this one, this one should just skip over + KeywordType::Memory | + 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{ Ok(0) +} + +pub struct Defineds { + pub memories: HashMap, + pub functions: HashMap, + pub constants: HashMap +} + +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 } \ No newline at end of file diff --git a/src/interpret/linux_x86_64/syscalls.rs b/src/interpret/linux_x86_64/syscalls.rs index c764c95..0b9e1b2 100644 --- a/src/interpret/linux_x86_64/syscalls.rs +++ b/src/interpret/linux_x86_64/syscalls.rs @@ -1,10 +1,10 @@ - -pub fn sys_write(sys_n: usize, fd: usize, buff: usize, count: usize, mem: &Vec ) -> usize { +#[allow(clippy::cast_possible_truncation)] +pub fn sys_write(sys_n: usize, fd: usize, buff: usize, count: usize, mem: &Vec ) -> usize { let mem = (*mem).clone(); // println!("{:?}", &mem[buff..(buff + count)]); // return 0 ; 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::(); match fd { diff --git a/src/interpret/mod.rs b/src/interpret/mod.rs index 031016e..1385744 100644 --- a/src/interpret/mod.rs +++ b/src/interpret/mod.rs @@ -1 +1,27 @@ -pub mod linux_x86_64; \ No newline at end of file +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, + pub value_s: Option, + 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 +} \ No newline at end of file diff --git a/src/lexer.rs b/src/lexer.rs index a1f41df..4943395 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -1,6 +1,5 @@ -use crate::{constants::{Token, TokenType}, preprocessor::preprocess, Args}; -use color_eyre::Result; +use crate::{constants::{Token, TokenType}, Args}; fn lex_word(s: String, tok_type: TokenType) -> (TokenType, String) { match s { @@ -89,7 +88,7 @@ fn lex_line(text: &str) -> Vec<(usize, String, TokenType)> { tokens } -pub fn lex + std::marker::Copy>(code: &str, file: S, args: &Args, preprocessing: bool) -> Result> { +pub fn lex(code: &str, file: &str, _args: &Args) -> Vec { let lines: Vec<(usize, &str)> = code .split(['\n', '\r']) .enumerate() @@ -104,14 +103,14 @@ pub fn lex + std::marker::Copy>(code: &str, file: S, args: &Args for (col, tok, tok_type) in lt { let (tok_type, tok) = lex_word(tok, tok_type); let t = Token{ - file: file.into(), + file: file.to_string(), line: row + 1, col, text: tok, typ: tok_type, value: None, addr: None, - op_typ: crate::constants::InstructionType::None + op_typ: crate::constants::OpType::Instruction(crate::constants::InstructionType::None) }; tokens.push(t); } @@ -121,9 +120,7 @@ pub fn lex + std::marker::Copy>(code: &str, file: S, args: &Args // for token in tokens.clone() { // println!("tok: {:?}", token.text); // } - if preprocessing { - tokens = preprocess(tokens, args)?; - } + - Ok(tokens) + tokens } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c85c814..5aa2839 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +#![allow(clippy::wildcard_imports)] +#![allow(clippy::too_many_lines)] mod constants; mod interpret; mod util; @@ -7,18 +9,14 @@ mod lexer; mod preprocessor; mod typechecker; mod precompiler; - -use std::fs; +mod config; +mod errors; +use config::*; +use std::{fs, collections::HashMap}; use clap::Parser; - -pub const DEFAULT_OUT_FILE: &str = "a.out"; -pub const DEFAULT_INCLUDES: [&str;2] = [ - "./include", - "~/.mclang/include", -]; - - +use color_eyre::Result; +use eyre::eyre; #[derive(Parser, Debug, Clone)] #[command(author, version, about, long_about = None)] @@ -53,38 +51,70 @@ pub struct Args { /// Unsafe mode, disables typechecking #[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')] //features: Vec, } -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{ + 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 Ok(code) = fs::read_to_string(&args.in_file) else { error!("Failed to read file {}, exiting!", &args.in_file); - return; - - }; - let Ok(tokens) = lexer::lex(&code, &args.in_file, &args, true) else { - error!("Lexing failed, exiting!"); - return; + return Ok(()); }; + + let tokens = lexer::lex(&code, args.in_file.as_str(), &args); - let mut parser = parser::Parser::new(tokens); - let Ok(tokens) = parser.parse() else { - error!("Parsing failed, exiting!"); - return; + let mut parser = parser::Parser::new(tokens, &args, None); + let tokens = match parser.parse(){ + Ok(t) => t, + Err(e) => { + error!("Parsing failed, exiting!"); + if crate::DEV_MODE { + return Err(e) + } + return Ok(()); + } }; - let Ok(tokens) = typechecker::typecheck(&tokens, &args) else { - error!("Typechecking failed, exiting!"); - return; + match typechecker::typecheck(tokens.clone(), &args, None, HashMap::new(), HashMap::new()) { + Ok(_) => (), + Err(e) => { + error!("Typechecking failed, exiting!"); + if crate::DEV_MODE { + return Err(e); + } + return Ok(()); + } }; let c = if args.compile && args.interpret { diff --git a/src/parser.rs b/src/parser.rs index 2e21f55..cd9d395 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,22 +1,27 @@ 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 eyre::eyre; pub fn cross_ref(mut program: Vec) -> Result> { let mut stack: Vec = Vec::new(); + for ip in 0..program.len() { let op = &program.clone()[ip]; + // println!("{op:?}"); match op.typ { - OpType::Keyword(KeywordType::If) | - OpType::Keyword(KeywordType::While) => { + // OpType::Keyword(KeywordType::FunctionDef) | + OpType::Keyword(KeywordType::If | KeywordType::While) => { stack.push(ip); } 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) { - 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")); } @@ -24,26 +29,41 @@ pub fn cross_ref(mut program: Vec) -> Result> { stack.push(ip); }, 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) || - program[block_ip].typ == OpType::Keyword(KeywordType::Else) { - - program[block_ip].jmp = ip; - program[ip].jmp = ip + 1; + match &program[block_ip].typ { + OpType::Keyword(KeywordType::If | KeywordType::Else) => { + program[block_ip].jmp = ip; + program[ip].jmp = ip + 1; + } - } else if program[block_ip].typ == OpType::Keyword(KeywordType::Do) { - program[ip].jmp = program[block_ip].jmp; - program[block_ip].jmp = ip + 1; - } else { - lerror!(&op.clone().loc,"'end' can only close 'if' blocks"); - return Err(eyre!("")); + OpType::Keyword(KeywordType::Do) => { + program[ip].jmp = program[block_ip].jmp; + program[block_ip].jmp = ip + 1; + } + OpType::Keyword(KeywordType::FunctionThen) => { + 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) => { - let while_ip = stack.pop().unwrap(); - program[ip].jmp = while_ip; + let Some(block_ip) = stack.pop() else { + lerror!(&op.loc, "Unclosed while-do block"); + return Err(eyre!("Cross referencing")); + }; + + program[ip].jmp = block_ip; stack.push(ip); } _ => () @@ -51,21 +71,31 @@ pub fn cross_ref(mut program: Vec) -> Result> { } 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")); } Ok(program.clone()) } -pub struct Parser { - tokens: Vec +pub struct Parser<'a> { + tokens: Vec, + pub preprocessor: Preprocessor<'a>, + #[allow(dead_code)] + args: &'a Args } -impl Parser { - pub fn new(file: Vec) -> Self { +impl<'a> Parser<'a> { + pub fn new(file: Vec, args: &'a Args, p: Option>) -> Self { + let pre = if let Some(p) = p {p} else { + Preprocessor::new(Vec::new(), args) + }; + Self{ - tokens: file + tokens: file, + preprocessor: pre, + args } } @@ -79,19 +109,19 @@ impl Parser { let pos = (token.file.clone(), token.line, token.col); match token.typ { 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) } else { 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 - tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.text.parse::()?, String::new(), token.file.clone(), token.line, token.col)); + tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.typ, token.text.parse::()?, String::new(), token.file.clone(), token.line, token.col)); }, 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 => { let c = token.text.clone(); @@ -100,27 +130,29 @@ impl Parser { 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>(s: &str, _pos: P) -> OpType { let n = s.parse::(); - if let Ok(_) = n { + if n.is_ok() { return OpType::Instruction(InstructionType::PushInt); } match s { //stack - "print" => OpType::Instruction(InstructionType::Print), + "_dbg_print" => OpType::Instruction(InstructionType::Print), "dup" => OpType::Instruction(InstructionType::Dup), "drop" => OpType::Instruction(InstructionType::Drop), "rot" => OpType::Instruction(InstructionType::Rot), @@ -146,9 +178,12 @@ pub fn lookup_word>(s: &str, _pos: P) -> OpType { // mem - "mem" => OpType::Instruction(InstructionType::Mem), "load8" => OpType::Instruction(InstructionType::Load8), "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), "syscall1" => OpType::Instruction(InstructionType::Syscall1), @@ -157,18 +192,31 @@ pub fn lookup_word>(s: &str, _pos: P) -> OpType { "syscall4" => OpType::Instruction(InstructionType::Syscall4), "syscall5" => OpType::Instruction(InstructionType::Syscall5), "syscall6" => OpType::Instruction(InstructionType::Syscall6), - "cast(bool" => OpType::Instruction(InstructionType::CastBool), + "cast(bool)" => OpType::Instruction(InstructionType::CastBool), "cast(ptr)" => OpType::Instruction(InstructionType::CastPtr), "cast(int)" => OpType::Instruction(InstructionType::CastInt), + "cast(void)" => OpType::Instruction(InstructionType::CastVoid), // block "if" => OpType::Keyword(KeywordType::If), "else" => OpType::Keyword(KeywordType::Else), "end" => OpType::Keyword(KeywordType::End), "while" => OpType::Keyword(KeywordType::While), "do" => OpType::Keyword(KeywordType::Do), - "macro" => OpType::Keyword(KeywordType::Macro), "include" => OpType::Keyword(KeywordType::Include), "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) } diff --git a/src/precompiler.rs b/src/precompiler.rs index 7b60624..9c4bc3e 100644 --- a/src/precompiler.rs +++ b/src/precompiler.rs @@ -2,7 +2,7 @@ use color_eyre::Result; 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, loc: &Loc) -> Result { if let Some(i) = stack.pop() { Ok(i) } else { @@ -11,23 +11,16 @@ fn stack_pop(stack: &mut Vec, loc: &Loc) -> Result { } } -pub fn precompile(tokens: &Vec) -> Result>{ +pub fn precompile(tokens: &Vec) -> Result>{ let mut stack: Vec = Vec::new(); - for token in tokens.iter() { - let typ = lookup_word(&token.text, &token.loc()); - match typ { + match token.typ.clone() { OpType::Instruction(i) => { - let loc = token.loc(); + let loc = token.loc.clone(); match i { InstructionType::PushInt => { - if let Ok(i) = token.text.parse::() { - stack.push(i); - } else { - lerror!(&token.loc(), "Bad number"); - return Err(eyre!("")); - } + stack.push(token.value); }, InstructionType::Plus => { let a = stack_pop(&mut stack, &loc)?; @@ -136,14 +129,14 @@ pub fn precompile(tokens: &Vec) -> Result>{ stack.push(b); } _ => { - lerror!(&token.loc(), "Unsupported precompiler instruction {:?}", i); + lerror!(&token.loc, "Unsupported precompiler instruction {:?}", i); dbg!(tokens); return Err(eyre!("")); } } } - _ => { - lerror!(&token.loc(), "Unsupported precompiler keyword {:?}", typ); + OpType::Keyword(_) => { + lerror!(&token.loc, "Unsupported precompiler keyword {:?}", token.typ); dbg!(tokens); return Err(eyre!("")); } diff --git a/src/preprocessor.rs b/src/preprocessor.rs index cdc6c89..719bc89 100644 --- a/src/preprocessor.rs +++ b/src/preprocessor.rs @@ -1,255 +1,475 @@ use std::collections::HashMap; +use std::ops::Deref; use std::path::{PathBuf, Path}; + use color_eyre::Result; 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::precompiler::precompile; -use crate::{lerror, lnote, Args, warn, linfo}; +use crate::{lerror, Args, warn, linfo, parser}; use crate::parser::lookup_word; -#[derive(Debug)] -pub struct Macro { + + +#[derive(Debug, Clone)] +pub struct Function { pub loc: Loc, - pub tokens: Vec + pub name: String } -type Macros = HashMap; -type Memories = HashMap; +#[derive(Debug, Clone)] +pub struct Constant { + pub loc: Loc, + pub name: String +} -pub fn preprocess(tokens: Vec, args: &Args) -> Result>{ +#[derive(Debug, Clone)] +pub struct Memory { + pub loc: Loc, + pub id: usize - - let mut program: Vec = 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!(¯o_name.loc(), "Bad macro name, expected {} but found {}", TokenType::Word.human(), macro_name.typ.human()); - return Err(eyre!("")); - } - let word = lookup_word(¯o_name.text, ¯o_name.loc()); - if word != OpType::Instruction(InstructionType::None) { - lerror!(¯o_name.loc(), "Macro name cannot be a built in word, got '{}'", word.human()); - return Err(eyre!("")); - } - - if macros.get(¯o_name.text.clone()).is_some() && crate::constants::ALLOW_MACRO_REDEFINITION { - lerror!(¯o_name.loc(), "Macro redefinition is not allowed"); - lnote!(¯os.get(¯o_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::>()); - - let mut include_code = String::new(); - - if include_path.text.chars().collect::>()[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 = 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::>().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, ¯os, &memories)?; - times += 1; - } - - - Ok(program) } -pub fn expand(tokens: Vec, macros: &Macros, mems: &Memories) -> Result> { - let mut program: Vec = Vec::new(); +type Functions = HashMap; +type Memories = HashMap; +type Constants = HashMap; - let mut rtokens = tokens; - rtokens.reverse(); +#[derive(Debug, Clone)] +pub struct Preprocessor<'a> { + pub program: Vec, + pub functions: Functions, + pub memories: Memories, + pub constants: Constants, + args: &'a Args +} - while !rtokens.is_empty() { - let op = rtokens.pop().unwrap(); - let op_type = lookup_word(&op.text, &op.loc()); - if op.typ == TokenType::Word { - match op_type { - OpType::Instruction(InstructionType::None) => { - let m = macros.get(&op.text); - let mem = mems.get(&op.text); - if let Some(m) = m { - program.append(&mut m.tokens.clone()); - } else - if let Some(mem) = mem { - let mut t = op; - t.addr = Some(*mem); - t.op_typ = InstructionType::MemUse; - program.push(t); - } - else { - lerror!(&op.loc(), "Unknown word '{}'", op.text.clone()); + +impl<'a> Preprocessor<'a> { + pub fn new(prog: Vec, args: &'a Args) -> Self { + Self { + program: prog, + args, + functions: HashMap::new(), + memories: HashMap::new(), + constants: HashMap::new(), + } + } + + + pub fn preprocess(&mut self) -> Result<&mut Preprocessor<'a>>{ + // println!("pre: has do tokens: {:?}", self.program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::>>()); + + let mut program: Vec = Vec::new(); + + 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!("")); } + + 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::>()); + + let mut include_code = String::new(); + let mut pth = PathBuf::new(); + if include_path.text.chars().collect::>()[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 = 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::>>()); + //* 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::>().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 = 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::>>()); + self.program = program; + // println!("{:#?}", self.program); + // println!("{:?}", self.program.last().unwrap()); + Ok(()) + } - Ok(program) + + + pub fn get_ops(&mut self) -> Vec { + self.program.clone() + } + pub fn is_word_available(&self, word: &Operator, typ: KeywordType) -> Result { + + 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() + } } \ No newline at end of file diff --git a/src/typechecker.rs b/src/typechecker.rs index c5e4302..a32c653 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -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 eyre::eyre; +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub struct Function { + loc: Loc, + args: Vec, + returns: Vec, +} -pub fn typecheck(ops: &[Operator], args: &Args) -> Result>{ +#[derive(Debug, Clone)] +pub struct Constant { + #[allow(dead_code)] + loc: Loc, + types: Vec, +} + +impl Function { + #[allow(dead_code)] + pub fn default() -> Self { + Self { + args: Vec::new(), + returns: Vec::new(), + loc: (String::new(), 0, 0) + } + } +} + +type Functions = HashMap; +type Constants = HashMap; + +pub fn typecheck(ops: Vec, args: &Args, init_types: Option>, funcs: HashMap, consts: HashMap) -> Result<(Vec, Functions, Constants)>{ if args.unsaf { if !args.quiet { warn!("Unsafe mode enabled, disabling typechecker, goodluck"); } - return Ok(ops.to_vec()); + return Ok((Vec::new(), HashMap::new(), HashMap::new())); } - - let mut stack: Vec = Vec::new(); - - for op in ops { + + let mut functions: HashMap = funcs; + let mut constants: HashMap = consts; + // let mut in_function: (String, Function, Loc) = (String::new(), Function::default(), (String::new(), 0, 0)); + let mut stack: Vec = if let Some(i) = init_types {i} else {Vec::new()}; + let mut stack_snapshots: Vec> = 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() { OpType::Keyword(keyword) => { match keyword { - KeywordType::If => { - stack_pop(&mut stack, &op, &[Types::Bool])?; - }, + KeywordType::If | KeywordType::Do => { 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 = 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::End | KeywordType::While | - KeywordType::Macro | KeywordType::Include | + KeywordType::Constant | 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) => { @@ -73,85 +220,42 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result>{ stack.push(a); 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, Types::Ptr])?; stack.push(Types::Int); }, - InstructionType::Plus => { - stack_pop(&mut stack, &op, &[Types::Int])?; - stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?; - stack.push(Types::Int); - }, - 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::Equals | + InstructionType::Gt | + InstructionType::Lt | + InstructionType::Ge | + InstructionType::Le | InstructionType::NotEquals => { - stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?; - stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?; + stack_pop(&mut stack, &op, &[Types::Int])?; + stack_pop(&mut stack, &op, &[Types::Int])?; 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 => { stack_pop(&mut stack, &op, &[Types::Int])?; stack_pop(&mut stack, &op, &[Types::Int])?; stack.push(Types::Int); stack.push(Types::Int); }, - InstructionType::Mul => { - stack_pop(&mut stack, &op, &[Types::Int])?; - stack_pop(&mut stack, &op, &[Types::Int])?; - stack.push(Types::Int); - }, - InstructionType::Mem => { - stack.push(Types::Ptr); - }, - InstructionType::Load8 => { + InstructionType::Load8 | + InstructionType::Load32 | + InstructionType::Load64 => { stack_pop(&mut stack, &op, &[Types::Ptr])?; 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::Ptr])?; }, @@ -216,16 +320,63 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result>{ stack_pop(&mut stack, &op, &[Types::Any])?; stack.push(Types::Int); }, + InstructionType::CastVoid => { + stack_pop(&mut stack, &op, &[Types::Any])?; + stack.push(Types::Any); + }, InstructionType::MemUse => { 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)) } diff --git a/src/util.rs b/src/util.rs index 107d7a6..15b41ac 100644 --- a/src/util.rs +++ b/src/util.rs @@ -66,6 +66,21 @@ pub mod logger { pub fn lnote>(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); } + + 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 { #[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()) }; } @@ -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! 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! 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()) }; } } } diff --git a/test.mcl b/test.mcl index 6f45b83..c2cfa73 100644 --- a/test.mcl +++ b/test.mcl @@ -1,6 +1,5 @@ -memory m 10 end +include "std.mcl" -m 69 store8 - - -m load8 print \ No newline at end of file +fn main with void returns void then + "hi\n" puts +done \ No newline at end of file