diff --git a/build.sh b/build.sh index 7fbfad4..0fa2191 100755 --- a/build.sh +++ b/build.sh @@ -8,8 +8,9 @@ dotnet build src/lang/Nub.Lang.CLI nub example > out/out.qbe nasm -g -felf64 src/runtime/runtime.asm -o out/runtime.o +nasm -g -felf64 src/runtime/core/syscall.asm -o out/syscall.o qbe out/out.qbe > out/out.s gcc -c -g out/out.s -o out/out.o -gcc -nostartfiles -o out/program out/runtime.o out/out.o \ No newline at end of file +gcc -nostartfiles -o out/program out/runtime.o out/syscall.o out/out.o \ No newline at end of file diff --git a/convert.py b/convert.py new file mode 100644 index 0000000..259fadf --- /dev/null +++ b/convert.py @@ -0,0 +1,556 @@ +import csv +import re +from typing import List, Dict, Tuple + +def parse_type_and_name(param_str: str) -> Tuple[str, str]: + """Parse a parameter string like 'const char *filename' or 'const char *const argv[]' into type and name.""" + if not param_str.strip(): + return "", "" + + # Clean up the parameter string + param_str = param_str.strip() + + # Handle array syntax like 'const char *const argv[]' + array_match = re.search(r'\[\]', param_str) + is_array = bool(array_match) + if is_array: + param_str = re.sub(r'\[\]', '', param_str).strip() + + # Remove 'const' qualifiers for type mapping (but keep track of them) + cleaned_param = re.sub(r'\bconst\b\s*', '', param_str).strip() + + # Handle pointer types like 'char *buf' or 'struct stat *statbuf' + if '*' in cleaned_param: + parts = cleaned_param.split('*') + base_type = parts[0].strip() + var_name = parts[1].strip() + + # Handle struct types + if base_type.startswith('struct '): + return '^u8', var_name # Generic pointer for structs + elif base_type.startswith('union '): + return '^u8', var_name # Generic pointer for unions + elif 'void' in base_type: + return '^u8', var_name # void pointer becomes generic pointer + elif 'char' in base_type: + if is_array: + return '^cstring', var_name # Array of strings + else: + return '^u8', var_name # char pointer + else: + # For other pointer types, use the mapped base type with pointer + mapped_base = map_c_type_to_custom(base_type) + return f'^{mapped_base}', var_name + + # Handle regular types like 'unsigned int fd', 'size_t count' + parts = cleaned_param.strip().split() + if len(parts) >= 2: + var_name = parts[-1] + type_parts = parts[:-1] + full_type = ' '.join(type_parts) + mapped_type = map_c_type_to_custom(full_type) + return mapped_type, var_name + elif len(parts) == 1: + # Single word - might be a type without variable name or variable without type + return "", parts[0] + + return "", "" + +def map_c_type_to_custom(c_type: str) -> str: + """Map C types to custom type system.""" + c_type = c_type.strip().lower() + + # Handle common C types + if 'unsigned int' in c_type or c_type == 'int': + return 'u32' + elif 'unsigned long' in c_type or c_type == 'long': + return 'u64' + elif 'size_t' in c_type or 'ssize_t' in c_type: + return 'u64' + elif 'off_t' in c_type or 'loff_t' in c_type: + return 'u64' + elif 'pid_t' in c_type or 'uid_t' in c_type or 'gid_t' in c_type: + return 'u32' + elif 'mode_t' in c_type or 'umode_t' in c_type: + return 'u32' + elif 'time_t' in c_type: + return 'u64' + elif 'key_t' in c_type: + return 'u32' + elif 'mqd_t' in c_type: + return 'u32' + elif 'clockid_t' in c_type: + return 'u32' + elif 'timer_t' in c_type: + return 'u32' + elif 'qid_t' in c_type: + return 'u32' + elif 'aio_context_t' in c_type: + return 'u64' + elif c_type == 'char': + return 'u8' + elif c_type == 'unsigned char': + return 'u8' + elif c_type == 'short' or 'short int' in c_type: + return 'u16' + elif c_type == 'unsigned short': + return 'u16' + elif 'void' in c_type: + return 'u8' # void maps to u8 for generic data + elif c_type.startswith('struct') or c_type.startswith('union'): + return 'u8' # Structs/unions map to u8 for generic handling + elif 'u32' in c_type or 'u64' in c_type: # Already in target format + return c_type + else: + return 'u32' # Default fallback + +def extract_function_name(syscall_name: str) -> str: + """Extract function name from syscall name like 'sys_read' -> 'read'.""" + if syscall_name.startswith('sys_'): + return syscall_name[4:] + elif syscall_name.startswith('stub_'): + return syscall_name[5:] + return syscall_name + +def clean_syscall_name(syscall_name: str) -> str: + """Clean syscall names that might have issues.""" + # Handle special cases + if 'NOT IMPLEMENTED' in syscall_name or 'REMOVED' in syscall_name: + return "" + return syscall_name.strip() + +def convert_csv_to_functions(csv_content: str) -> str: + """Convert CSV content to function definitions.""" + lines = csv_content.strip().split('\n') + + # Parse header to understand column positions + header = [col.strip() for col in lines[0].split(',')] + + # Find the positions of key columns + syscall_num_idx = 0 # %rax + syscall_name_idx = 1 # System call + param_indices = [i for i, col in enumerate(header) if col.startswith('%') and col != '%rax'] + + functions = [] + + for line_num, line in enumerate(lines[1:], 2): # Skip header, start from line 2 + if not line.strip(): + continue + + # Handle CSV parsing more carefully - some lines have trailing commas + cols = [col.strip() for col in line.split(',')] + + # Ensure we have enough columns + while len(cols) < len(header): + cols.append('') + + # Extract syscall number and name + syscall_num = cols[syscall_num_idx] if syscall_num_idx < len(cols) else "" + syscall_name = cols[syscall_name_idx] if syscall_name_idx < len(cols) else "" + + # Clean and validate syscall name + syscall_name = clean_syscall_name(syscall_name) + if not syscall_num or not syscall_name or syscall_name in ['NOT IMPLEMENTED', 'REMOVED IN Linux 2.6']: + continue + + # Extract function name + func_name = extract_function_name(syscall_name) + if not func_name: + continue + + # Parse parameters + params = [] + param_names = [] + + for param_idx in param_indices: + if param_idx < len(cols): + param_str = cols[param_idx] + if param_str.strip(): + param_type, param_name = parse_type_and_name(param_str) + if param_type and param_name: + params.append(f"{param_name}: {param_type}") + param_names.append(param_name) + + # Generate function definition + if params: + param_list = ", ".join(params) + else: + param_list = "" + + call_params = ", ".join([syscall_num] + param_names) + + # function_def = f"func {func_name}({param_list}) {{\n call({call_params})\n}}" + # functions.append(function_def) + functions.append(f"const {func_name}: i64 = {syscall_num}") + + return "\n\n".join(functions) + +# Test with a file if provided +def process_file(filename: str) -> str: + """Process a CSV file and return the converted functions.""" + try: + with open(filename, 'r') as f: + content = f.read() + return convert_csv_to_functions(content) + except FileNotFoundError: + return f"Error: File '{filename}' not found." + except Exception as e: + return f"Error processing file: {str(e)}" + +# Example usage with file reading +def main(): + # If running with the uploaded file + try: + # Try to read from the uploaded file + with open('paste.txt', 'r') as f: + csv_content = f.read() + result = convert_csv_to_functions(csv_content) + print("Generated functions from paste.txt:") + print("=" * 50) + print(result) + except FileNotFoundError: + # Fallback to sample data + sample_csv = """%rax, System call, %rdi, %rsi, %rdx, %r10, %r8, %r9 +0, sys_read, unsigned int fd, char *buf, size_t count, , , +1, sys_write, unsigned int fd, const char *buf, size_t count, , , +2, sys_open, const char *filename, int flags, int mode, , , +3, sys_close, unsigned int fd, , , , , +4, sys_stat, const char *filename, struct stat *statbuf, , , , +5, sys_fstat, unsigned int fd, struct stat *statbuf, , , , +6, sys_lstat, fconst char *filename, struct stat *statbuf, , , , +7, sys_poll, struct poll_fd *ufds, unsigned int nfds, long timeout_msecs, , , +8, sys_lseek, unsigned int fd, off_t offset, unsigned int origin, , , +9, sys_mmap, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off +10, sys_mprotect, unsigned long start, size_t len, unsigned long prot, , , +11, sys_munmap, unsigned long addr, size_t len, , , , +12, sys_brk, unsigned long brk, , , , , +13, sys_rt_sigaction, int sig, const struct sigaction *act, struct sigaction *oact, size_t sigsetsize, , +14, sys_rt_sigprocmask, int how, sigset_t *nset, sigset_t *oset, size_t sigsetsize, , +15, sys_rt_sigreturn, unsigned long __unused, , , , , +16, sys_ioctl, unsigned int fd, unsigned int cmd, unsigned long arg, , , +17, sys_pread64, unsigned long fd, char *buf, size_t count, loff_t pos, , +18, sys_pwrite64, unsigned int fd, const char *buf, size_t count, loff_t pos, , +19, sys_readv, unsigned long fd, const struct iovec *vec, unsigned long vlen, , , +20, sys_writev, unsigned long fd, const struct iovec *vec, unsigned long vlen, , , +21, sys_access, const char *filename, int mode, , , , +22, sys_pipe, int *filedes, , , , , +23, sys_select, int n, fd_set *inp, fd_set *outp, fd_set*exp, struct timeval *tvp, +24, sys_sched_yield, , , , , , +25, sys_mremap, unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr, +26, sys_msync, unsigned long start, size_t len, int flags, , , +27, sys_mincore, unsigned long start, size_t len, unsigned char *vec, , , +28, sys_madvise, unsigned long start, size_t len_in, int behavior, , , +29, sys_shmget, key_t key, size_t size, int shmflg, , , +30, sys_shmat, int shmid, char *shmaddr, int shmflg, , , +31, sys_shmctl, int shmid, int cmd, struct shmid_ds *buf, , , +32, sys_dup, unsigned int fildes, , , , , +33, sys_dup2, unsigned int oldfd, unsigned int newfd, , , , +34, sys_pause, , , , , , +35, sys_nanosleep, struct timespec *rqtp, struct timespec *rmtp, , , , +36, sys_getitimer, int which, struct itimerval *value, , , , +37, sys_alarm, unsigned int seconds, , , , , +38, sys_setitimer, int which, struct itimerval *value, struct itimerval *ovalue, , , +39, sys_getpid, , , , , , +40, sys_sendfile, int out_fd, int in_fd, off_t *offset, size_t count, , +41, sys_socket, int family, int type, int protocol, , , +42, sys_connect, int fd, struct sockaddr *uservaddr, int addrlen, , , +43, sys_accept, int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen, , , +44, sys_sendto, int fd, void *buff, size_t len, unsigned flags, struct sockaddr *addr, int addr_len +45, sys_recvfrom, int fd, void *ubuf, size_t size, unsigned flags, struct sockaddr *addr, int *addr_len +46, sys_sendmsg, int fd, struct msghdr *msg, unsigned flags, , , +47, sys_recvmsg, int fd, struct msghdr *msg, unsigned int flags, , , +48, sys_shutdown, int fd, int how, , , , +49, sys_bind, int fd, struct sokaddr *umyaddr, int addrlen, , , +50, sys_listen, int fd, int backlog, , , , +51, sys_getsockname, int fd, struct sockaddr *usockaddr, int *usockaddr_len, , , +52, sys_getpeername, int fd, struct sockaddr *usockaddr, int *usockaddr_len, , , +53, sys_socketpair, int family, int type, int protocol, int *usockvec, , +54, sys_setsockopt, int fd, int level, int optname, char *optval, int optlen, +55, sys_getsockopt, int fd, int level, int optname, char *optval, int *optlen, +56, sys_clone, unsigned long clone_flags, unsigned long newsp, void *parent_tid, void *child_tid, unsigned int tid, +57, sys_fork, , , , , , +58, sys_vfork, , , , , , +59, sys_execve, const char *filename, const char *const argv[], const char *const envp[], , , +60, sys_exit, int error_code, , , , , +61, sys_wait4, pid_t upid, int *stat_addr, int options, struct rusage *ru, , +62, sys_kill, pid_t pid, int sig, , , , +63, sys_uname, struct old_utsname *name, , , , , +64, sys_semget, key_t key, int nsems, int semflg, , , +65, sys_semop, int semid, struct sembuf *tsops, unsigned nsops, , , +66, sys_semctl, int semid, int semnum, int cmd, union semun arg, , +67, sys_shmdt, char *shmaddr, , , , , +68, sys_msgget, key_t key, int msgflg, , , , +69, sys_msgsnd, int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg, , +70, sys_msgrcv, int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg, +71, sys_msgctl, int msqid, int cmd, struct msqid_ds *buf, , , +72, sys_fcntl, unsigned int fd, unsigned int cmd, unsigned long arg, , , +73, sys_flock, unsigned int fd, unsigned int cmd, , , , +74, sys_fsync, unsigned int fd, , , , , +75, sys_fdatasync, unsigned int fd, , , , , +76, sys_truncate, const char *path, long length, , , , +77, sys_ftruncate, unsigned int fd, unsigned long length, , , , +78, sys_getdents, unsigned int fd, struct linux_dirent *dirent, unsigned int count, , , +79, sys_getcwd, char *buf, unsigned long size, , , , +80, sys_chdir, const char *filename, , , , , +81, sys_fchdir, unsigned int fd, , , , , +82, sys_rename, const char *oldname, const char *newname, , , , +83, sys_mkdir, const char *pathname, int mode, , , , +84, sys_rmdir, const char *pathname, , , , , +85, sys_creat, const char *pathname, int mode, , , , +86, sys_link, const char *oldname, const char *newname, , , , +87, sys_unlink, const char *pathname, , , , , +88, sys_symlink, const char *oldname, const char *newname, , , , +89, sys_readlink, const char *path, char *buf, int bufsiz, , , +90, sys_chmod, const char *filename, mode_t mode, , , , +91, sys_fchmod, unsigned int fd, mode_t mode, , , , +92, sys_chown, const char *filename, uid_t user, gid_t group, , , +93, sys_fchown, unsigned int fd, uid_t user, gid_t group, , , +94, sys_lchown, const char *filename, uid_t user, gid_t group, , , +95, sys_umask, int mask, , , , , +96, sys_gettimeofday, struct timeval *tv, struct timezone *tz, , , , +97, sys_getrlimit, unsigned int resource, struct rlimit *rlim, , , , +98, sys_getrusage, int who, struct rusage *ru, , , , +99, sys_sysinfo, struct sysinfo *info, , , , , +100, sys_times, struct tms *tbuf, , , , , +101, sys_ptrace, long request, long pid, unsigned long addr, unsigned long data, , +102, sys_getuid, , , , , , +103, sys_syslog, int type, char *buf, int len, , , +104, sys_getgid, , , , , , +105, sys_setuid, uid_t uid, , , , , +106, sys_setgid, gid_t gid, , , , , +107, sys_geteuid, , , , , , +108, sys_getegid, , , , , , +109, sys_setpgid, pid_t pid, pid_t pgid, , , , +110, sys_getppid, , , , , , +111, sys_getpgrp, , , , , , +112, sys_setsid, , , , , , +113, sys_setreuid, uid_t ruid, uid_t euid, , , , +114, sys_setregid, gid_t rgid, gid_t egid, , , , +115, sys_getgroups, int gidsetsize, gid_t *grouplist, , , , +116, sys_setgroups, int gidsetsize, gid_t *grouplist, , , , +117, sys_setresuid, uid_t *ruid, uid_t *euid, uid_t *suid, , , +118, sys_getresuid, uid_t *ruid, uid_t *euid, uid_t *suid, , , +119, sys_setresgid, gid_t rgid, gid_t egid, gid_t sgid, , , +120, sys_getresgid, gid_t *rgid, gid_t *egid, gid_t *sgid, , , +121, sys_getpgid, pid_t pid, , , , , +122, sys_setfsuid, uid_t uid, , , , , +123, sys_setfsgid, gid_t gid, , , , , +124, sys_getsid, pid_t pid, , , , , +125, sys_capget, cap_user_header_t header, cap_user_data_t dataptr, , , , +126, sys_capset, cap_user_header_t header, const cap_user_data_t data, , , , +127, sys_rt_sigpending, sigset_t *set, size_t sigsetsize, , , , +128, sys_rt_sigtimedwait, const sigset_t *uthese, siginfo_t *uinfo, const struct timespec *uts, size_t sigsetsize, , +129, sys_rt_sigqueueinfo, pid_t pid, int sig, siginfo_t *uinfo, , , +130, sys_rt_sigsuspend, sigset_t *unewset, size_t sigsetsize, , , , +131, sys_sigaltstack, const stack_t *uss, stack_t *uoss, , , , +132, sys_utime, char *filename, struct utimbuf *times, , , , +133, sys_mknod, const char *filename, umode_t mode, unsigned dev, , , +134, sys_uselib, NOT IMPLEMENTED, , , , , +135, sys_personality, unsigned int personality, , , , , +136, sys_ustat, unsigned dev, struct ustat *ubuf, , , , +137, sys_statfs, const char *pathname, struct statfs *buf, , , , +138, sys_fstatfs, unsigned int fd, struct statfs *buf, , , , +139, sys_sysfs, int option, unsigned long arg1, unsigned long arg2, , , +140, sys_getpriority, int which, int who, , , , +141, sys_setpriority, int which, int who, int niceval, , , +142, sys_sched_setparam, pid_t pid, struct sched_param *param, , , , +143, sys_sched_getparam, pid_t pid, struct sched_param *param, , , , +144, sys_sched_setscheduler, pid_t pid, int policy, struct sched_param *param, , , +145, sys_sched_getscheduler, pid_t pid, , , , , +146, sys_sched_get_priority_max, int policy, , , , , +147, sys_sched_get_priority_min, int policy, , , , , +148, sys_sched_rr_get_interval, pid_t pid, struct timespec *interval, , , , +149, sys_mlock, unsigned long start, size_t len, , , , +150, sys_munlock, unsigned long start, size_t len, , , , +151, sys_mlockall, int flags, , , , , +152, sys_munlockall, , , , , , +153, sys_vhangup, , , , , , +154, sys_modify_ldt, int func, void *ptr, unsigned long bytecount, , , +155, sys_pivot_root, const char *new_root, const char *put_old, , , , +156, sys__sysctl, struct __sysctl_args *args, , , , , +157, sys_prctl, int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, , unsigned long arg5 +158, sys_arch_prctl, struct task_struct *task, int code, unsigned long *addr, , , +159, sys_adjtimex, struct timex *txc_p, , , , , +160, sys_setrlimit, unsigned int resource, struct rlimit *rlim, , , , +161, sys_chroot, const char *filename, , , , , +162, sys_sync, , , , , , +163, sys_acct, const char *name, , , , , +164, sys_settimeofday, struct timeval *tv, struct timezone *tz, , , , +165, sys_mount, char *dev_name, char *dir_name, char *type, unsigned long flags, void *data, +166, sys_umount2, const char *target, int flags, , , , +167, sys_swapon, const char *specialfile, int swap_flags, , , , +168, sys_swapoff, const char *specialfile, , , , , +169, sys_reboot, int magic1, int magic2, unsigned int cmd, void *arg, , +170, sys_sethostname, char *name, int len, , , , +171, sys_setdomainname, char *name, int len, , , , +172, sys_iopl, unsigned int level, struct pt_regs *regs, , , , +173, sys_ioperm, unsigned long from, unsigned long num, int turn_on, , , +174, sys_create_module, REMOVED IN Linux 2.6, , , , , +175, sys_init_module, void *umod, unsigned long len, const char *uargs, , , +176, sys_delete_module, const chat *name_user, unsigned int flags, , , , +177, sys_get_kernel_syms, REMOVED IN Linux 2.6, , , , , +178, sys_query_module, REMOVED IN Linux 2.6, , , , , +179, sys_quotactl, unsigned int cmd, const char *special, qid_t id, void *addr, , +180, sys_nfsservctl, NOT IMPLEMENTED, , , , , +181, sys_getpmsg, NOT IMPLEMENTED, , , , , +182, sys_putpmsg, NOT IMPLEMENTED, , , , , +183, sys_afs_syscall, NOT IMPLEMENTED, , , , , +184, sys_tuxcall, NOT IMPLEMENTED, , , , , +185, sys_security, NOT IMPLEMENTED, , , , , +186, sys_gettid, , , , , , +187, sys_readahead, int fd, loff_t offset, size_t count, , , +188, sys_setxattr, const char *pathname, const char *name, const void *value, size_t size, int flags, +189, sys_lsetxattr, const char *pathname, const char *name, const void *value, size_t size, int flags, +190, sys_fsetxattr, int fd, const char *name, const void *value, size_t size, int flags, +191, sys_getxattr, const char *pathname, const char *name, void *value, size_t size, , +192, sys_lgetxattr, const char *pathname, const char *name, void *value, size_t size, , +193, sys_fgetxattr, int fd, const har *name, void *value, size_t size, , +194, sys_listxattr, const char *pathname, char *list, size_t size, , , +195, sys_llistxattr, const char *pathname, char *list, size_t size, , , +196, sys_flistxattr, int fd, char *list, size_t size, , , +197, sys_removexattr, const char *pathname, const char *name, , , , +198, sys_lremovexattr, const char *pathname, const char *name, , , , +199, sys_fremovexattr, int fd, const char *name, , , , +200, sys_tkill, pid_t pid, ing sig, , , , +201, sys_time, time_t *tloc, , , , , +202, sys_futex, u32 *uaddr, int op, u32 val, struct timespec *utime, u32 *uaddr2, u32 val3 +203, sys_sched_setaffinity, pid_t pid, unsigned int len, unsigned long *user_mask_ptr, , , +204, sys_sched_getaffinity, pid_t pid, unsigned int len, unsigned long *user_mask_ptr, , , +205, sys_set_thread_area, NOT IMPLEMENTED. Use arch_prctl, , , , , +206, sys_io_setup, unsigned nr_events, aio_context_t *ctxp, , , , +207, sys_io_destroy, aio_context_t ctx, , , , , +208, sys_io_getevents, aio_context_t ctx_id, long min_nr, long nr, struct io_event *events, , +209, sys_io_submit, aio_context_t ctx_id, long nr, struct iocb **iocbpp, , , +210, sys_io_cancel, aio_context_t ctx_id, struct iocb *iocb, struct io_event *result, , , +211, sys_get_thread_area, NOT IMPLEMENTED. Use arch_prctl, , , , , +212, sys_lookup_dcookie, u64 cookie64, long buf, long len, , , +213, sys_epoll_create, int size, , , , , +214, sys_epoll_ctl_old, NOT IMPLEMENTED, , , , , +215, sys_epoll_wait_old, NOT IMPLEMENTED, , , , , +216, sys_remap_file_pages, unsigned long start, unsigned long size, unsigned long prot, unsigned long pgoff, unsigned long flags, +217, sys_getdents64, unsigned int fd, struct linux_dirent64 *dirent, unsigned int count, , , +218, sys_set_tid_address, int *tidptr, , , , , +219, sys_restart_syscall, , , , , , +220, sys_semtimedop, int semid, struct sembuf *tsops, unsigned nsops, const struct timespec *timeout, , +221, sys_fadvise64, int fd, loff_t offset, size_t len, int advice, , +222, sys_timer_create, const clockid_t which_clock, struct sigevent *timer_event_spec, timer_t *created_timer_id, , , +223, sys_timer_settime, timer_t timer_id, int flags, const struct itimerspec *new_setting, struct itimerspec *old_setting, , +224, sys_timer_gettime, timer_t timer_id, struct itimerspec *setting, , , , +225, sys_timer_getoverrun, timer_t timer_id, , , , , +226, sys_timer_delete, timer_t timer_id, , , , , +227, sys_clock_settime, const clockid_t which_clock, const struct timespec *tp, , , , +228, sys_clock_gettime, const clockid_t which_clock, struct timespec *tp, , , , +229, sys_clock_getres, const clockid_t which_clock, struct timespec *tp, , , , +230, sys_clock_nanosleep, const clockid_t which_clock, int flags, const struct timespec *rqtp, struct timespec *rmtp, , +231, sys_exit_group, int error_code, , , , , +232, sys_epoll_wait, int epfd, struct epoll_event *events, int maxevents, int timeout, , +233, sys_epoll_ctl, int epfd, int op, int fd, struct epoll_event *event, , +234, sys_tgkill, pid_t tgid, pid_t pid, int sig, , , +235, sys_utimes, char *filename, struct timeval *utimes, , , , +236, sys_vserver, NOT IMPLEMENTED, , , , , +237, sys_mbind, unsigned long start, unsigned long len, unsigned long mode, unsigned long *nmask, unsigned long maxnode, unsigned flags +238, sys_set_mempolicy, int mode, unsigned long *nmask, unsigned long maxnode, , , +239, sys_get_mempolicy, int *policy, unsigned long *nmask, unsigned long maxnode, unsigned long addr, unsigned long flags, +240, sys_mq_open, const char *u_name, int oflag, mode_t mode, struct mq_attr *u_attr, , +241, sys_mq_unlink, const char *u_name, , , , , +242, sys_mq_timedsend, mqd_t mqdes, const char *u_msg_ptr, size_t msg_len, unsigned int msg_prio, const stuct timespec *u_abs_timeout, +243, sys_mq_timedreceive, mqd_t mqdes, char *u_msg_ptr, size_t msg_len, unsigned int *u_msg_prio, const struct timespec *u_abs_timeout, +244, sys_mq_notify, mqd_t mqdes, const struct sigevent *u_notification, , , , +245, sys_mq_getsetattr, mqd_t mqdes, const struct mq_attr *u_mqstat, struct mq_attr *u_omqstat, , , +246, sys_kexec_load, unsigned long entry, unsigned long nr_segments, struct kexec_segment *segments, unsigned long flags, , +247, sys_waitid, int which, pid_t upid, struct siginfo *infop, int options, struct rusage *ru, +248, sys_add_key, const char *_type, const char *_description, const void *_payload, size_t plen, , +249, sys_request_key, const char *_type, const char *_description, const char *_callout_info, key_serial_t destringid, , +250, sys_keyctl, int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, +251, sys_ioprio_set, int which, int who, int ioprio, , , +252, sys_ioprio_get, int which, int who, , , , +253, sys_inotify_init, , , , , , +254, sys_inotify_add_watch, int fd, const char *pathname, u32 mask, , , +255, sys_inotify_rm_watch, int fd, __s32 wd, , , , +256, sys_migrate_pages, pid_t pid, unsigned long maxnode, const unsigned long *old_nodes, const unsigned long *new_nodes, , +257, sys_openat, int dfd, const char *filename, int flags, int mode, , +258, sys_mkdirat, int dfd, const char *pathname, int mode, , , +259, sys_mknodat, int dfd, const char *filename, int mode, unsigned dev, , +260, sys_fchownat, int dfd, const char *filename, uid_t user, gid_t group, int flag, +261, sys_futimesat, int dfd, const char *filename, struct timeval *utimes, , , +262, sys_newfstatat, int dfd, const char *filename, struct stat *statbuf, int flag, , +263, sys_unlinkat, int dfd, const char *pathname, int flag, , , +264, sys_renameat, int oldfd, const char *oldname, int newfd, const char *newname, , +265, sys_linkat, int oldfd, const char *oldname, int newfd, const char *newname, int flags, +266, sys_symlinkat, const char *oldname, int newfd, const char *newname, , , +267, sys_readlinkat, int dfd, const char *pathname, char *buf, int bufsiz, , +268, sys_fchmodat, int dfd, const char *filename, mode_t mode, , , +269, sys_faccessat, int dfd, const char *filename, int mode, , , +270, sys_pselect6, int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timespec *tsp, void *sig +271, sys_ppoll, struct pollfd *ufds, unsigned int nfds, struct timespec *tsp, const sigset_t *sigmask, size_t sigsetsize, +272, sys_unshare, unsigned long unshare_flags, , , , , +273, sys_set_robust_list, struct robust_list_head *head, size_t len, , , , +274, sys_get_robust_list, int pid, struct robust_list_head **head_ptr, size_t *len_ptr, , , +275, sys_splice, int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags +276, sys_tee, int fdin, int fdout, size_t len, unsigned int flags, , +277, sys_sync_file_range, long fd, loff_t offset, loff_t bytes, long flags, , +278, sys_vmsplice, int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags, , +279, sys_move_pages, pid_t pid, unsigned long nr_pages, const void **pages, const int *nodes, int *status, int flags +280, sys_utimensat, int dfd, const char *filename, struct timespec *utimes, int flags, , +281, sys_epoll_pwait, int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *sigmask, size_t sigsetsize +282, sys_signalfd, int ufd, sigset_t *user_mask, size_t sizemask, , , +283, sys_timerfd_create, int clockid, int flags, , , , +284, sys_eventfd, unsigned int count, , , , , +285, sys_fallocate, long fd, long mode, loff_t offset, loff_t len, , +286, sys_timerfd_settime, int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr, , +287, sys_timerfd_gettime, int ufd, struct itimerspec *otmr, , , , +288, sys_accept4, int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen, int flags, , +289, sys_signalfd4, int ufd, sigset_t *user_mask, size_t sizemask, int flags, , +290, sys_eventfd2, unsigned int count, int flags, , , , +291, sys_epoll_create1, int flags, , , , , +292, sys_dup3, unsigned int oldfd, unsigned int newfd, int flags, , , +293, sys_pipe2, int *filedes, int flags, , , , +294, sys_inotify_init1, int flags, , , , , +295, sys_preadv, unsigned long fd, const struct iovec *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h, +296, sys_pwritev, unsigned long fd, const struct iovec *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h, +297, sys_rt_tgsigqueueinfo, pid_t tgid, pid_t pid, int sig, siginfo_t *uinfo, , +298, sys_perf_event_open, struct perf_event_attr *attr_uptr, pid_t pid, int cpu, int group_fd, unsigned long flags, +299, sys_recvmmsg, int fd, struct msghdr *mmsg, unsigned int vlen, unsigned int flags, struct timespec *timeout, +300, sys_fanotify_init, unsigned int flags, unsigned int event_f_flags, , , , +301, sys_fanotify_mark, long fanotify_fd, long flags, __u64 mask, long dfd, long pathname, +302, sys_prlimit64, pid_t pid, unsigned int resource, const struct rlimit64 *new_rlim, struct rlimit64 *old_rlim, , +303, sys_name_to_handle_at, int dfd, const char *name, struct file_handle *handle, int *mnt_id, int flag, +304, sys_open_by_handle_at, int dfd, const char *name, struct file_handle *handle, int *mnt_id, int flags, +305, sys_clock_adjtime, clockid_t which_clock, struct timex *tx, , , , +306, sys_syncfs, int fd, , , , , +307, sys_sendmmsg, int fd, struct mmsghdr *mmsg, unsigned int vlen, unsigned int flags, , +308, sys_setns, int fd, int nstype, , , , +309, sys_getcpu, unsigned *cpup, unsigned *nodep, struct getcpu_cache *unused, , , +310, sys_process_vm_readv, pid_t pid, const struct iovec *lvec, unsigned long liovcnt, const struct iovec *rvec, unsigned long riovcnt, unsigned long flags +311, sys_process_vm_writev, pid_t pid, const struct iovec *lvec, unsigned long liovcnt, const struct iovcc *rvec, unsigned long riovcnt, unsigned long flags +312, sys_kcmp, pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2, +313, sys_finit_module, int fd, const char __user *uargs, int flags, , , +314, sys_sched_setattr, pid_t pid, struct sched_attr __user *attr, unsigned int flags, , , +315, sys_sched_getattr, pid_t pid, struct sched_attr __user *attr, unsigned int size, unsigned int flags, , +316, sys_renameat2, int olddfd, const char __user *oldname, int newdfd, const char __user *newname, unsigned int flags, +317, sys_seccomp, unsigned int op, unsigned int flags, const char __user *uargs, , , +318, sys_getrandom, char __user *buf, size_t count, unsigned int flags, , , +319, sys_memfd_create, const char __user *uname_ptr, unsigned int flags, , , , +320, sys_kexec_file_load, int kernel_fd, int initrd_fd, unsigned long cmdline_len, const char __user *cmdline_ptr, unsigned long flags, +321, sys_bpf, int cmd, union bpf_attr *attr, unsigned int size, , , +322, stub_execveat, int dfd, const char __user *filename, const char __user *const __user *argv, const char __user *const __user *envp, int flags, +323, userfaultfd, int flags, , , , , +324, membarrier, int cmd, int flags, , , , +325, mlock2, unsigned long start, size_t len, int flags, , , +326, copy_file_range, int fd_in, loff_t __user *off_in, int fd_out, loff_t __user * off_out, size_t len, unsigned int flags +327, preadv2, unsigned long fd, const struct iovec __user *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h, int flags +328, pwritev2, unsigned long fd, const struct iovec __user *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h, int flags +329, pkey_mprotect, , , , , , +330, pkey_alloc, , , , , , +331, pkey_free, , , , , , +332, statx, , , , , , +333, io_pgetevents, , , , , , +334, rseq, , , , , , +335, pkey_mprotect, , , , , , +""" + + result = convert_csv_to_functions(sample_csv) + print(result) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/core/syscall.nub b/example/core/syscall.nub new file mode 100644 index 0000000..961491c --- /dev/null +++ b/example/core/syscall.nub @@ -0,0 +1,340 @@ +namespace sys + +let read: i64 = 0 +let write: i64 = 1 +let open: i64 = 2 +let close: i64 = 3 +let stat: i64 = 4 +let fstat: i64 = 5 +let lstat: i64 = 6 +let poll: i64 = 7 +let lseek: i64 = 8 +let mmap: i64 = 9 +let mprotect: i64 = 10 +let munmap: i64 = 11 +let brk: i64 = 12 +let rt_sigaction: i64 = 13 +let rt_sigprocmask: i64 = 14 +let rt_sigreturn: i64 = 15 +let ioctl: i64 = 16 +let pread64: i64 = 17 +let pwrite64: i64 = 18 +let readv: i64 = 19 +let writev: i64 = 20 +let access: i64 = 21 +let pipe: i64 = 22 +let select: i64 = 23 +let sched_yield: i64 = 24 +let mremap: i64 = 25 +let msync: i64 = 26 +let mincore: i64 = 27 +let madvise: i64 = 28 +let shmget: i64 = 29 +let shmat: i64 = 30 +let shmctl: i64 = 31 +let dup: i64 = 32 +let dup2: i64 = 33 +let pause: i64 = 34 +let nanosleep: i64 = 35 +let getitimer: i64 = 36 +let alarm: i64 = 37 +let setitimer: i64 = 38 +let getpid: i64 = 39 +let sendfile: i64 = 40 +let socket: i64 = 41 +let connect: i64 = 42 +let accept: i64 = 43 +let sendto: i64 = 44 +let recvfrom: i64 = 45 +let sendmsg: i64 = 46 +let recvmsg: i64 = 47 +let shutdown: i64 = 48 +let bind: i64 = 49 +let listen: i64 = 50 +let getsockname: i64 = 51 +let getpeername: i64 = 52 +let socketpair: i64 = 53 +let setsockopt: i64 = 54 +let getsockopt: i64 = 55 +let clone: i64 = 56 +let fork: i64 = 57 +let vfork: i64 = 58 +let execve: i64 = 59 +let exit: i64 = 60 +let wait4: i64 = 61 +let kill: i64 = 62 +let uname: i64 = 63 +let semget: i64 = 64 +let semop: i64 = 65 +let semctl: i64 = 66 +let shmdt: i64 = 67 +let msgget: i64 = 68 +let msgsnd: i64 = 69 +let msgrcv: i64 = 70 +let msgctl: i64 = 71 +let fcntl: i64 = 72 +let flock: i64 = 73 +let fsync: i64 = 74 +let fdatasync: i64 = 75 +let truncate: i64 = 76 +let ftruncate: i64 = 77 +let getdents: i64 = 78 +let getcwd: i64 = 79 +let chdir: i64 = 80 +let fchdir: i64 = 81 +let rename: i64 = 82 +let mkdir: i64 = 83 +let rmdir: i64 = 84 +let creat: i64 = 85 +let link: i64 = 86 +let unlink: i64 = 87 +let symlink: i64 = 88 +let readlink: i64 = 89 +let chmod: i64 = 90 +let fchmod: i64 = 91 +let chown: i64 = 92 +let fchown: i64 = 93 +let lchown: i64 = 94 +let umask: i64 = 95 +let gettimeofday: i64 = 96 +let getrlimit: i64 = 97 +let getrusage: i64 = 98 +let sysinfo: i64 = 99 +let times: i64 = 100 +let ptrace: i64 = 101 +let getuid: i64 = 102 +let syslog: i64 = 103 +let getgid: i64 = 104 +let setuid: i64 = 105 +let setgid: i64 = 106 +let geteuid: i64 = 107 +let getegid: i64 = 108 +let setpgid: i64 = 109 +let getppid: i64 = 110 +let getpgrp: i64 = 111 +let setsid: i64 = 112 +let setreuid: i64 = 113 +let setregid: i64 = 114 +let getgroups: i64 = 115 +let setgroups: i64 = 116 +let setresuid: i64 = 117 +let getresuid: i64 = 118 +let setresgid: i64 = 119 +let getresgid: i64 = 120 +let getpgid: i64 = 121 +let setfsuid: i64 = 122 +let setfsgid: i64 = 123 +let getsid: i64 = 124 +let capget: i64 = 125 +let capset: i64 = 126 +let rt_sigpending: i64 = 127 +let rt_sigtimedwait: i64 = 128 +let rt_sigqueueinfo: i64 = 129 +let rt_sigsuspend: i64 = 130 +let sigaltstack: i64 = 131 +let utime: i64 = 132 +let mknod: i64 = 133 +let uselib: i64 = 134 +let personality: i64 = 135 +let ustat: i64 = 136 +let statfs: i64 = 137 +let fstatfs: i64 = 138 +let sysfs: i64 = 139 +let getpriority: i64 = 140 +let setpriority: i64 = 141 +let sched_setparam: i64 = 142 +let sched_getparam: i64 = 143 +let sched_setscheduler: i64 = 144 +let sched_getscheduler: i64 = 145 +let sched_get_priority_max: i64 = 146 +let sched_get_priority_min: i64 = 147 +let sched_rr_get_interval: i64 = 148 +let mlock: i64 = 149 +let munlock: i64 = 150 +let mlockall: i64 = 151 +let munlockall: i64 = 152 +let vhangup: i64 = 153 +let modify_ldt: i64 = 154 +let pivot_root: i64 = 155 +let _sysctl: i64 = 156 +let prctl: i64 = 157 +let arch_prctl: i64 = 158 +let adjtimex: i64 = 159 +let setrlimit: i64 = 160 +let chroot: i64 = 161 +let sync: i64 = 162 +let acct: i64 = 163 +let settimeofday: i64 = 164 +let mount: i64 = 165 +let umount2: i64 = 166 +let swapon: i64 = 167 +let swapoff: i64 = 168 +let reboot: i64 = 169 +let sethostname: i64 = 170 +let setdomainname: i64 = 171 +let iopl: i64 = 172 +let ioperm: i64 = 173 +let create_module: i64 = 174 +let init_module: i64 = 175 +let delete_module: i64 = 176 +let get_kernel_syms: i64 = 177 +let query_module: i64 = 178 +let quotactl: i64 = 179 +let nfsservctl: i64 = 180 +let getpmsg: i64 = 181 +let putpmsg: i64 = 182 +let afs_syscall: i64 = 183 +let tuxcall: i64 = 184 +let security: i64 = 185 +let gettid: i64 = 186 +let readahead: i64 = 187 +let setxattr: i64 = 188 +let lsetxattr: i64 = 189 +let fsetxattr: i64 = 190 +let getxattr: i64 = 191 +let lgetxattr: i64 = 192 +let fgetxattr: i64 = 193 +let listxattr: i64 = 194 +let llistxattr: i64 = 195 +let flistxattr: i64 = 196 +let removexattr: i64 = 197 +let lremovexattr: i64 = 198 +let fremovexattr: i64 = 199 +let tkill: i64 = 200 +let time: i64 = 201 +let futex: i64 = 202 +let sched_setaffinity: i64 = 203 +let sched_getaffinity: i64 = 204 +let set_thread_area: i64 = 205 +let io_setup: i64 = 206 +let io_destroy: i64 = 207 +let io_getevents: i64 = 208 +let io_submit: i64 = 209 +let io_cancel: i64 = 210 +let get_thread_area: i64 = 211 +let lookup_dcookie: i64 = 212 +let epoll_create: i64 = 213 +let epoll_ctl_old: i64 = 214 +let epoll_wait_old: i64 = 215 +let remap_file_pages: i64 = 216 +let getdents64: i64 = 217 +let set_tid_address: i64 = 218 +let restart_syscall: i64 = 219 +let semtimedop: i64 = 220 +let fadvise64: i64 = 221 +let timer_create: i64 = 222 +let timer_settime: i64 = 223 +let timer_gettime: i64 = 224 +let timer_getoverrun: i64 = 225 +let timer_delete: i64 = 226 +let clock_settime: i64 = 227 +let clock_gettime: i64 = 228 +let clock_getres: i64 = 229 +let clock_nanosleep: i64 = 230 +let exit_group: i64 = 231 +let epoll_wait: i64 = 232 +let epoll_ctl: i64 = 233 +let tgkill: i64 = 234 +let utimes: i64 = 235 +let vserver: i64 = 236 +let mbind: i64 = 237 +let set_mempolicy: i64 = 238 +let get_mempolicy: i64 = 239 +let mq_open: i64 = 240 +let mq_unlink: i64 = 241 +let mq_timedsend: i64 = 242 +let mq_timedreceive: i64 = 243 +let mq_notify: i64 = 244 +let mq_getsetattr: i64 = 245 +let kexec_load: i64 = 246 +let waitid: i64 = 247 +let add_key: i64 = 248 +let request_key: i64 = 249 +let keyctl: i64 = 250 +let ioprio_set: i64 = 251 +let ioprio_get: i64 = 252 +let inotify_init: i64 = 253 +let inotify_add_watch: i64 = 254 +let inotify_rm_watch: i64 = 255 +let migrate_pages: i64 = 256 +let openat: i64 = 257 +let mkdirat: i64 = 258 +let mknodat: i64 = 259 +let fchownat: i64 = 260 +let futimesat: i64 = 261 +let newfstatat: i64 = 262 +let unlinkat: i64 = 263 +let renameat: i64 = 264 +let linkat: i64 = 265 +let symlinkat: i64 = 266 +let readlinkat: i64 = 267 +let fchmodat: i64 = 268 +let faccessat: i64 = 269 +let pselect6: i64 = 270 +let ppoll: i64 = 271 +let unshare: i64 = 272 +let set_robust_list: i64 = 273 +let get_robust_list: i64 = 274 +let splice: i64 = 275 +let tee: i64 = 276 +let sync_file_range: i64 = 277 +let vmsplice: i64 = 278 +let move_pages: i64 = 279 +let utimensat: i64 = 280 +let epoll_pwait: i64 = 281 +let signalfd: i64 = 282 +let timerfd_create: i64 = 283 +let eventfd: i64 = 284 +let fallocate: i64 = 285 +let timerfd_settime: i64 = 286 +let timerfd_gettime: i64 = 287 +let accept4: i64 = 288 +let signalfd4: i64 = 289 +let eventfd2: i64 = 290 +let epoll_create1: i64 = 291 +let dup3: i64 = 292 +let pipe2: i64 = 293 +let inotify_init1: i64 = 294 +let preadv: i64 = 295 +let pwritev: i64 = 296 +let rt_tgsigqueueinfo: i64 = 297 +let perf_event_open: i64 = 298 +let recvmmsg: i64 = 299 +let fanotify_init: i64 = 300 +let fanotify_mark: i64 = 301 +let prlimit64: i64 = 302 +let name_to_handle_at: i64 = 303 +let open_by_handle_at: i64 = 304 +let clock_adjtime: i64 = 305 +let syncfs: i64 = 306 +let sendmmsg: i64 = 307 +let setns: i64 = 308 +let getcpu: i64 = 309 +let process_vm_readv: i64 = 310 +let process_vm_writev: i64 = 311 +let kcmp: i64 = 312 +let finit_module: i64 = 313 +let sched_setattr: i64 = 314 +let sched_getattr: i64 = 315 +let renameat2: i64 = 316 +let seccomp: i64 = 317 +let getrandom: i64 = 318 +let memfd_create: i64 = 319 +let kexec_file_load: i64 = 320 +let bpf: i64 = 321 +let execveat: i64 = 322 +let userfaultfd: i64 = 323 +let membarrier: i64 = 324 +let mlock2: i64 = 325 +let copy_file_range: i64 = 326 +let preadv2: i64 = 327 +let pwritev2: i64 = 328 +let pkey_mprotect: i64 = 329 +let pkey_alloc: i64 = 330 +let pkey_free: i64 = 331 +let statx: i64 = 332 +let io_pgetevents: i64 = 333 +let rseq: i64 = 334 +let pkey_mprotect: i64 = 335 + +extern func call(num: i64, ...args: any) calls core_syscall diff --git a/example/interop/bindings.nub b/example/interop/c.nub similarity index 100% rename from example/interop/bindings.nub rename to example/interop/c.nub diff --git a/example/main.nub b/example/main.nub index 61b8abc..41ff5e3 100644 --- a/example/main.nub +++ b/example/main.nub @@ -1,15 +1,5 @@ namespace main -struct Human { - name: string - age: i64 -} - export func main(args: []^string) { - let me = alloc Human { - name = "oliver" - age = 32 - } - - c::printf("%s is %d years old\n", me.name, me.age) + sys::call(60, 0) } \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Generation/Generator.cs b/src/lang/Nub.Lang/Frontend/Generation/Generator.cs index d4d5603..668644b 100644 --- a/src/lang/Nub.Lang/Frontend/Generation/Generator.cs +++ b/src/lang/Nub.Lang/Frontend/Generation/Generator.cs @@ -21,7 +21,6 @@ public class Generator private Stack _continueLabels = []; private int _variableIndex; private int _labelIndex; - private int _funcIndex; private bool _codeIsReachable = true; private Dictionary _funcNames = []; @@ -35,7 +34,6 @@ public class Generator _breakLabels = []; _continueLabels = []; _variableIndex = 0; - _funcIndex = 0; _labelIndex = 0; _codeIsReachable = true; @@ -45,12 +43,14 @@ public class Generator _builder.AppendLine(); } + var localFuncIndex = 0; + foreach (var funcSignature in _sourceFiles.SelectMany(f => f.Definitions).OfType()) { switch (funcSignature) { case ExternFuncDefinitionNode externFuncDefinitionNode: - _funcNames[funcSignature] = "$" + externFuncDefinitionNode.Name; + _funcNames[funcSignature] = "$" + externFuncDefinitionNode.CallName; break; case LocalFuncDefinitionNode localFuncDefinitionNode: if (localFuncDefinitionNode.Exported) @@ -59,8 +59,7 @@ public class Generator } else { - var funcName = GenFuncName(); - _funcNames[funcSignature] = funcName; + _funcNames[funcSignature] = $"$func{++localFuncIndex}"; } break; @@ -88,7 +87,6 @@ public class Generator private enum TypeContext { - Struct, FuncDef, FuncCall, } @@ -97,30 +95,6 @@ public class Generator { return context switch { - TypeContext.Struct => type switch - { - NubArrayType => "l", // TODO: Arrays in structs are pointers for now - NubPointerType => "l", - NubPrimitiveType primitiveType => primitiveType.Kind switch - { - PrimitiveTypeKind.I64 => "l", - PrimitiveTypeKind.I32 => "w", - PrimitiveTypeKind.I16 => "h", - PrimitiveTypeKind.I8 => "b", - PrimitiveTypeKind.U64 => "l", - PrimitiveTypeKind.U32 => "w", - PrimitiveTypeKind.U16 => "h", - PrimitiveTypeKind.U8 => "b", - PrimitiveTypeKind.F64 => "d", - PrimitiveTypeKind.F32 => "s", - PrimitiveTypeKind.Bool => "w", - PrimitiveTypeKind.String => "l", // TODO: Strings in structs are pointers for now - PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in structs"), - _ => throw new ArgumentOutOfRangeException() - }, - NubStructType => throw new NotImplementedException(), - _ => throw new ArgumentOutOfRangeException(nameof(type)) - }, TypeContext.FuncDef => type switch { NubArrayType => "l", @@ -143,6 +117,7 @@ public class Generator _ => throw new ArgumentOutOfRangeException() }, NubStructType structType => $":{structType.Namespace}_{structType.Name}", + NubFixedArrayType => "l", _ => throw new ArgumentOutOfRangeException(nameof(type)) }, TypeContext.FuncCall => type switch @@ -167,6 +142,7 @@ public class Generator _ => throw new ArgumentOutOfRangeException() }, NubStructType structType => $":{structType.Namespace}_{structType.Name}", + NubFixedArrayType => "l", _ => throw new ArgumentOutOfRangeException(nameof(type)) }, _ => throw new ArgumentOutOfRangeException(nameof(context), context, null) @@ -197,6 +173,7 @@ public class Generator _ => throw new ArgumentOutOfRangeException() }, NubStructType => "l", + NubFixedArrayType => "l", _ => throw new ArgumentOutOfRangeException(nameof(type)) }}"; } @@ -225,6 +202,7 @@ public class Generator _ => throw new ArgumentOutOfRangeException() }, NubStructType => "l", + NubFixedArrayType => "l", _ => throw new ArgumentOutOfRangeException(nameof(type)) }}"; } @@ -253,11 +231,12 @@ public class Generator _ => throw new ArgumentOutOfRangeException() }, NubStructType => "l", + NubFixedArrayType => "l", _ => throw new ArgumentOutOfRangeException(nameof(type)) }}"; } - private int QbeTypeSize(NubType type) + private int SizeOf(NubType type) { switch (type) { @@ -291,16 +270,20 @@ public class Generator case NubStructType nubStructType: { var definition = LookupStructDefinition(nubStructType.Namespace, nubStructType.Name); - return definition.Fields.Sum(f => QbeTypeSize(f.Type)); + return definition.Fields.Sum(f => SizeOf(f.Type)); } case NubPointerType: case NubArrayType: { return 8; } + case NubFixedArrayType nubFixedArrayType: + { + return SizeOf(nubFixedArrayType.ElementType) * nubFixedArrayType.Capacity; + } default: { - throw new NotImplementedException(); + throw new UnreachableException(); } } } @@ -313,6 +296,7 @@ public class Generator NubPointerType => false, NubPrimitiveType => false, NubStructType => true, + NubFixedArrayType => true, _ => throw new ArgumentOutOfRangeException(nameof(type)) }; } @@ -368,7 +352,7 @@ public class Generator } var pointerName = GenVarName(); - _builder.AppendLine($" {pointerName} {QBEAssign(parameter.Type)} alloc8 {QbeTypeSize(parameter.Type)}"); + _builder.AppendLine($" {pointerName} {QBEAssign(parameter.Type)} alloc8 {SizeOf(parameter.Type)}"); _builder.AppendLine($" storel %{parameterName}, {pointerName}"); _variables[parameter.Name] = new Variable @@ -403,8 +387,42 @@ public class Generator private void GenerateStructDefinition(StructDefinitionNode structDefinition) { - var fields = structDefinition.Fields.Select(f => QBEType(f.Type, TypeContext.Struct)); - _builder.AppendLine($"type :{structDefinition.Name} = {{ {string.Join(", ", fields)} }}"); + _builder.Append($"type :{structDefinition.Namespace}_{structDefinition.Name} = {{ "); + foreach (var structDefinitionField in structDefinition.Fields) + { + var fieldDefinition = GenerateFieldType(structDefinitionField.Type); + _builder.Append(fieldDefinition + ", "); + } + _builder.AppendLine("}"); + } + + private string GenerateFieldType(NubType type) + { + return type switch + { + NubArrayType => "l", + NubPointerType => "l", + NubPrimitiveType primitiveType => primitiveType.Kind switch + { + PrimitiveTypeKind.I64 => "l", + PrimitiveTypeKind.I32 => "w", + PrimitiveTypeKind.I16 => "h", + PrimitiveTypeKind.I8 => "b", + PrimitiveTypeKind.U64 => "l", + PrimitiveTypeKind.U32 => "w", + PrimitiveTypeKind.U16 => "h", + PrimitiveTypeKind.U8 => "b", + PrimitiveTypeKind.F64 => "d", + PrimitiveTypeKind.F32 => "s", + PrimitiveTypeKind.Bool => "w", + PrimitiveTypeKind.String => "l", + PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in structs"), + _ => throw new ArgumentOutOfRangeException() + }, + NubStructType structType => $":{structType.Namespace}_{structType.Name}", + NubFixedArrayType fixedArrayType => $"b {SizeOf(fixedArrayType)}", + _ => throw new ArgumentOutOfRangeException(nameof(type)) + }; } private void GenerateStatement(StatementNode statement) @@ -451,31 +469,59 @@ public class Generator private void GenerateArrayIndexAssignment(ArrayIndexAssignmentNode arrayIndexAssignment) { - var arrayType = (NubArrayType)arrayIndexAssignment.ArrayIndexAccess.Array.Type; - var array = GenerateExpression(arrayIndexAssignment.ArrayIndexAccess.Array); var index = GenerateExpression(arrayIndexAssignment.ArrayIndexAccess.Index); - GenerateArrayBoundsCheck(array, index); - var value = GenerateExpression(arrayIndexAssignment.Value); - var startName = GenVarName(); - _builder.AppendLine($" {startName} =l add {array}, 8"); - - var adjustedIndex = GenVarName(); - _builder.AppendLine($" {adjustedIndex} =l mul {index}, {QbeTypeSize(arrayType.BaseType)}"); - - var offsetName = GenVarName(); - _builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}"); - - if (IsLargeType(arrayType.BaseType)) + switch (arrayIndexAssignment.ArrayIndexAccess.Array.Type) { - _builder.AppendLine($" blit {value}, {offsetName}, {QbeTypeSize(arrayType.BaseType)}"); - } - else - { - _builder.AppendLine($" {QBEStore(arrayType.BaseType)} {value}, {offsetName}"); + case NubArrayType arrayType: + { + var startName = GenVarName(); + _builder.AppendLine($" {startName} =l add {array}, 8"); + + var adjustedIndex = GenVarName(); + _builder.AppendLine($" {adjustedIndex} =l mul {index}, {SizeOf(arrayType.ElementType)}"); + + var offsetName = GenVarName(); + _builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}"); + + if (IsLargeType(arrayType.ElementType)) + { + _builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(arrayType.ElementType)}"); + } + else + { + _builder.AppendLine($" {QBEStore(arrayType.ElementType)} {value}, {offsetName}"); + } + break; + } + case NubFixedArrayType fixedArrayType: + { + var startName = GenVarName(); + _builder.AppendLine($" {startName} =l add {array}, 8"); + + var adjustedIndex = GenVarName(); + _builder.AppendLine($" {adjustedIndex} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}"); + + var offsetName = GenVarName(); + _builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}"); + + if (IsLargeType(fixedArrayType.ElementType)) + { + _builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(fixedArrayType.ElementType)}"); + } + else + { + _builder.AppendLine($" {QBEStore(fixedArrayType.ElementType)} {value}, {offsetName}"); + } + break; + } + default: + { + throw new UnreachableException(); + } } } @@ -508,7 +554,7 @@ public class Generator if (IsLargeType(dereferenceAssignment.Value.Type)) { - _builder.AppendLine($" blit {value}, {location}, {QbeTypeSize(dereferenceAssignment.Value.Type)}"); + _builder.AppendLine($" blit {value}, {location}, {SizeOf(dereferenceAssignment.Value.Type)}"); } else { @@ -555,7 +601,14 @@ public class Generator var value = GenerateExpression(memberAssignment.Value); - throw new NotImplementedException(); + if (IsLargeType(memberAssignment.Value.Type)) + { + _builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(memberAssignment.Value.Type)}"); + } + else + { + _builder.AppendLine($" {QBEStore(memberAssignment.Value.Type)} {value}, {offsetName}"); + } } private void GenerateReturn(ReturnNode @return) @@ -579,30 +632,31 @@ public class Generator private void GenerateVariableDeclaration(VariableDeclarationNode variableDeclaration) { - var pointerName = GenVarName(); - var type = variableDeclaration.ExplicitType.Value ?? variableDeclaration.Value.Value?.Type!; - _builder.AppendLine($" {pointerName} {QBEAssign(type)} alloc8 {QbeTypeSize(type)}"); - + string pointerName; + if (variableDeclaration.Value.HasValue) { var result = GenerateExpression(variableDeclaration.Value.Value); - if (IsLargeType(type)) { - _builder.AppendLine($" blit {result}, {pointerName}, {QbeTypeSize(type)}"); + pointerName = result; } else { + pointerName = GenVarName(); + _builder.AppendLine($" {pointerName} {QBEAssign(type)} alloc8 {SizeOf(type)}"); _builder.AppendLine($" {QBEStore(type)} {result}, {pointerName}"); } } else { + pointerName = GenVarName(); + _builder.AppendLine($" {pointerName} {QBEAssign(type)} alloc8 {SizeOf(type)}"); if (IsLargeType(type)) { - _builder.AppendLine($" blit 0, {pointerName}, {QbeTypeSize(type)}"); + _builder.AppendLine($" call $nub_memset(l {pointerName}, ub 0, l {SizeOf(type)})"); } else { @@ -648,6 +702,7 @@ public class Generator BinaryExpressionNode binaryExpression => GenerateBinaryExpression(binaryExpression), CastNode cast => GenerateCast(cast), DereferenceNode dereference => GenerateDereference(dereference), + FixedArrayInitializerNode fixedArrayInitializer => GenerateFixedArrayInitializer(fixedArrayInitializer), FuncCallNode funcCallExpression => GenerateFuncCall(funcCallExpression), IdentifierNode identifier => GenerateIdentifier(identifier), LiteralNode literal => GenerateLiteral(literal), @@ -660,29 +715,56 @@ public class Generator private string GenerateArrayIndex(ArrayIndexAccessNode arrayIndexAccess) { - var arrayType = ((NubArrayType)arrayIndexAccess.Array.Type).BaseType; - var array = GenerateExpression(arrayIndexAccess.Array); var index = GenerateExpression(arrayIndexAccess.Index); - GenerateArrayBoundsCheck(array, index); - var firstItemPointerName = GenVarName(); - _builder.AppendLine($" {firstItemPointerName} =l add {array}, 8"); - var offsetPointerName = GenVarName(); - _builder.AppendLine($" {offsetPointerName} =l mul {index}, {QbeTypeSize(arrayType)}"); - var resultPointerName = GenVarName(); - _builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}"); + switch (arrayIndexAccess.Array.Type) + { + case NubArrayType arrayType: + { + var firstItemPointerName = GenVarName(); + _builder.AppendLine($" {firstItemPointerName} =l add {array}, 8"); + var offsetPointerName = GenVarName(); + _builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(arrayType.ElementType)}"); + var resultPointerName = GenVarName(); + _builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}"); - if (IsLargeType(arrayType)) - { - return resultPointerName; - } - else - { - var outputName = GenVarName(); - _builder.AppendLine($" {outputName} {QBEAssign(arrayType)} {QBELoad(arrayType)} {resultPointerName}"); - return outputName; + if (IsLargeType(arrayType.ElementType)) + { + return resultPointerName; + } + else + { + var outputName = GenVarName(); + _builder.AppendLine($" {outputName} {QBEAssign(arrayType.ElementType)} {QBELoad(arrayType.ElementType)} {resultPointerName}"); + return outputName; + } + } + case NubFixedArrayType fixedArrayType: + { + var firstItemPointerName = GenVarName(); + _builder.AppendLine($" {firstItemPointerName} =l add {array}, 8"); + var offsetPointerName = GenVarName(); + _builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}"); + var resultPointerName = GenVarName(); + _builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}"); + + if (IsLargeType(fixedArrayType.ElementType)) + { + return resultPointerName; + } + else + { + var outputName = GenVarName(); + _builder.AppendLine($" {outputName} {QBEAssign(fixedArrayType.ElementType)} {QBELoad(fixedArrayType.ElementType)} {resultPointerName}"); + return outputName; + } + } + default: + { + throw new UnreachableException(); + } } } @@ -714,7 +796,7 @@ public class Generator { var capacity = GenerateExpression(arrayInitializer.Capacity); var capacityInBytes = GenVarName(); - _builder.AppendLine($" {capacityInBytes} =l mul {capacity}, {QbeTypeSize(arrayInitializer.ElementType)}"); + _builder.AppendLine($" {capacityInBytes} =l mul {capacity}, {SizeOf(arrayInitializer.ElementType)}"); var totalArraySize = GenVarName(); _builder.AppendLine($" {totalArraySize} =l add {capacityInBytes}, 8"); var outputName = GenVarName(); @@ -1483,7 +1565,7 @@ public class Generator var structDefinition = LookupStructDefinition(structInitializer.StructType.Namespace, structInitializer.StructType.Name); var structVar = GenVarName(); - var size = structDefinition.Fields.Sum(x => QbeTypeSize(x.Type)); + var size = structDefinition.Fields.Sum(x => SizeOf(x.Type)); _builder.AppendLine($" {structVar} =l alloc8 {size}"); foreach (var field in structDefinition.Fields) @@ -1498,7 +1580,7 @@ public class Generator if (IsLargeType(field.Type)) { - _builder.AppendLine($" blit {var}, {offsetName}, {QbeTypeSize(field.Type)}"); + _builder.AppendLine($" blit {var}, {offsetName}, {SizeOf(field.Type)}"); } else { @@ -1513,7 +1595,7 @@ public class Generator if (IsLargeType(field.Type)) { - _builder.AppendLine($" blit {var}, {offsetName}, {QbeTypeSize(field.Type)}"); + _builder.AppendLine($" blit {var}, {offsetName}, {SizeOf(field.Type)}"); } else { @@ -1620,6 +1702,20 @@ public class Generator } } + private string GenerateFixedArrayInitializer(FixedArrayInitializerNode fixedArrayInitializer) + { + var capacityInBytes = SizeOf(fixedArrayInitializer.Type); + var outputName = GenVarName(); + _builder.AppendLine($" {outputName} =l alloc8 {capacityInBytes + 8}"); + _builder.AppendLine($" storel {fixedArrayInitializer.Capacity}, {outputName}"); + + var dataPtr = GenVarName(); + _builder.AppendLine($" {dataPtr} =l add {outputName}, 8"); + _builder.AppendLine($" call $nub_memset(l {dataPtr}, w 0, l {capacityInBytes})"); + + return outputName; + } + private string GenerateFuncCall(FuncCallNode funcCall) { var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList()); @@ -1664,11 +1760,6 @@ public class Generator return $"%v{++_variableIndex}"; } - private string GenFuncName() - { - return $"$f{++_funcIndex}"; - } - private string GenLabelName() { return $"@l{++_labelIndex}"; @@ -1694,7 +1785,7 @@ public class Generator private int LookupMemberOffset(StructDefinitionNode structDefinition, string member) { - return structDefinition.Fields.TakeWhile(f => f.Name != member).Sum(f => QbeTypeSize(f.Type)); + return structDefinition.Fields.TakeWhile(f => f.Name != member).Sum(f => SizeOf(f.Type)); } private class Variable diff --git a/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs b/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs index dbe0918..989e5ba 100644 --- a/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs +++ b/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs @@ -18,6 +18,7 @@ public class Lexer ["alloc"] = Symbol.Alloc, ["struct"] = Symbol.Struct, ["let"] = Symbol.Let, + ["calls"] = Symbol.Calls, }; private static readonly Dictionary Modifiers = new() diff --git a/src/lang/Nub.Lang/Frontend/Lexing/SymbolToken.cs b/src/lang/Nub.Lang/Frontend/Lexing/SymbolToken.cs index baa5502..24fcc56 100644 --- a/src/lang/Nub.Lang/Frontend/Lexing/SymbolToken.cs +++ b/src/lang/Nub.Lang/Frontend/Lexing/SymbolToken.cs @@ -42,5 +42,6 @@ public enum Symbol DoubleColon, Namespace, Let, - Alloc + Alloc, + Calls } \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Definitions/FuncDefinitionNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Definitions/FuncDefinitionNode.cs index 8aa012b..9f03f68 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Definitions/FuncDefinitionNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Definitions/FuncDefinitionNode.cs @@ -16,6 +16,7 @@ public class FuncParameter(string name, NubType type, bool variadic) public interface IFuncSignature { public string Name { get; } + public string Namespace { get; } public List Parameters { get; } public Optional ReturnType { get; } @@ -53,9 +54,10 @@ public interface IFuncSignature public string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}"; } -public class LocalFuncDefinitionNode(IReadOnlyList tokens, Optional documentation, string name, List parameters, BlockNode body, Optional returnType, bool exported) : DefinitionNode(tokens, documentation), IFuncSignature +public class LocalFuncDefinitionNode(IReadOnlyList tokens, Optional documentation, string name, string @namespace, List parameters, BlockNode body, Optional returnType, bool exported) : DefinitionNode(tokens, documentation), IFuncSignature { public string Name { get; } = name; + public string Namespace { get; } = @namespace; public List Parameters { get; } = parameters; public BlockNode Body { get; } = body; public Optional ReturnType { get; } = returnType; @@ -64,9 +66,11 @@ public class LocalFuncDefinitionNode(IReadOnlyList tokens, Optional $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}"; } -public class ExternFuncDefinitionNode(IReadOnlyList tokens, Optional documentation, string name, List parameters, Optional returnType) : DefinitionNode(tokens, documentation), IFuncSignature +public class ExternFuncDefinitionNode(IReadOnlyList tokens, Optional documentation, string name, string @namespace, string callName, List parameters, Optional returnType) : DefinitionNode(tokens, documentation), IFuncSignature { public string Name { get; } = name; + public string Namespace { get; } = @namespace; + public string CallName { get; } = callName; public List Parameters { get; } = parameters; public Optional ReturnType { get; } = returnType; diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Definitions/StructDefinitionNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Definitions/StructDefinitionNode.cs index f3e603a..1a1975b 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Definitions/StructDefinitionNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Definitions/StructDefinitionNode.cs @@ -11,8 +11,9 @@ public class StructField(string name, NubType type, Optional val public Optional Value { get; } = value; } -public class StructDefinitionNode(IReadOnlyList tokens, Optional documentation, string name, List fields) : DefinitionNode(tokens, documentation) +public class StructDefinitionNode(IReadOnlyList tokens, Optional documentation, string name, string @namespace, List fields) : DefinitionNode(tokens, documentation) { public string Name { get; } = name; + public string Namespace { get; } = @namespace; public List Fields { get; } = fields; } \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs index 8573c59..1bdbba4 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs @@ -1,4 +1,5 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using Nub.Lang.Diagnostics; using Nub.Lang.Frontend.Lexing; using Nub.Lang.Frontend.Parsing.Definitions; @@ -116,7 +117,14 @@ public class Parser .Build()); } - return new ExternFuncDefinitionNode(GetTokensForNode(startIndex), documentation, name.Value, parameters, returnType); + var callName = name.Value; + + if (TryExpectSymbol(Symbol.Calls)) + { + callName = ExpectIdentifier().Value; + } + + return new ExternFuncDefinitionNode(GetTokensForNode(startIndex), documentation, name.Value, _namespace, callName, parameters, returnType); } var body = ParseBlock(); @@ -131,7 +139,7 @@ public class Parser .Build()); } - return new LocalFuncDefinitionNode(GetTokensForNode(startIndex), documentation, name.Value, parameters, body, returnType, exported); + return new LocalFuncDefinitionNode(GetTokensForNode(startIndex), documentation, name.Value, _namespace, parameters, body, returnType, exported); } private StructDefinitionNode ParseStruct(int startIndex, List _, Optional documentation) @@ -158,7 +166,7 @@ public class Parser variables.Add(new StructField(variableName, variableType, variableValue)); } - return new StructDefinitionNode(GetTokensForNode(startIndex), documentation, name, variables); + return new StructDefinitionNode(GetTokensForNode(startIndex), documentation, name, _namespace, variables); } private FuncParameter ParseFuncParameter() @@ -521,11 +529,35 @@ public class Parser } case Symbol.OpenBracket: { - var capacity = ParseExpression(); - ExpectSymbol(Symbol.CloseBracket); - var type = ParseType(); + if (Peek().TryGetValue(out var capacityToken) && capacityToken is LiteralToken { Type: NubPrimitiveType { Kind: PrimitiveTypeKind.I64 } } literalToken) + { + var capacity = int.Parse(literalToken.Value); + Next(); + ExpectSymbol(Symbol.CloseBracket); + var elementType = ParseType(); + + if (capacity > 0) + { + expr = new FixedArrayInitializerNode(GetTokensForNode(startIndex), elementType, capacity); + } + else + { + throw new ParseException(Diagnostic + .Error("Fixed array size must be a positive integer") + .WithHelp("Use a positive integer literal for the array size") + .At(literalToken) + .Build()); + } + } + else + { + var capacity = ParseExpression(); + ExpectSymbol(Symbol.CloseBracket); + var type = ParseType(); - expr = new ArrayInitializerNode(GetTokensForNode(startIndex), capacity, type); + expr = new ArrayInitializerNode(GetTokensForNode(startIndex), capacity, type); + } + break; } case Symbol.Alloc: @@ -657,12 +689,32 @@ public class Parser if (TryExpectSymbol(Symbol.OpenBracket)) { - ExpectSymbol(Symbol.CloseBracket); - var baseType = ParseType(); - return new NubArrayType(baseType); + if (Peek().TryGetValue(out var token) && token is LiteralToken { Type: NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }, Value: var sizeValue }) + { + Next(); + ExpectSymbol(Symbol.CloseBracket); + var baseType = ParseType(); + + var size = int.Parse(sizeValue); + + if (size > 0) + { + return new NubFixedArrayType(baseType, size); + } + else + { + throw new UnreachableException(); + } + } + else + { + ExpectSymbol(Symbol.CloseBracket); + var baseType = ParseType(); + return new NubArrayType(baseType); + } } - if (!Peek().TryGetValue(out var token)) + if (!Peek().TryGetValue(out var peekToken)) { throw new ParseException(Diagnostic .Error("Unexpected end of file while parsing type") @@ -674,9 +726,9 @@ public class Parser throw new ParseException(Diagnostic .Error("Invalid type syntax") .WithHelp("Expected type name, '^' for pointer, or '[]' for array") - .At(token) + .At(peekToken) .Build()); - } +} private Token ExpectToken() { @@ -803,9 +855,9 @@ public class Parser } } - private Optional Peek() + private Optional Peek(int offset = 0) { - var peekIndex = _index; + var peekIndex = _index + offset; while (peekIndex < _tokens.Count && _tokens[peekIndex] is DocumentationToken) { peekIndex++; diff --git a/src/lang/Nub.Lang/Frontend/Typing/NubType.cs b/src/lang/Nub.Lang/Frontend/Typing/NubType.cs index 3f6b7fa..542170b 100644 --- a/src/lang/Nub.Lang/Frontend/Typing/NubType.cs +++ b/src/lang/Nub.Lang/Frontend/Typing/NubType.cs @@ -6,7 +6,22 @@ public abstract class NubType { public static bool IsCompatibleWith(NubType sourceType, NubType targetType) { - return targetType.Equals(NubPrimitiveType.Any) || sourceType.Equals(targetType); + if (targetType.Equals(NubPrimitiveType.Any) || sourceType.Equals(targetType)) + { + return true; + } + + if (sourceType is NubFixedArrayType fixedArray && targetType is NubArrayType array && IsCompatibleWith(fixedArray.ElementType, array.ElementType)) + { + return true; + } + + if (sourceType.Equals(NubPrimitiveType.String) && targetType is NubArrayType arrayType && IsCompatibleWith(NubPrimitiveType.U8, arrayType.ElementType)) + { + return true; + } + + return false; } public abstract override bool Equals(object? obj); @@ -55,27 +70,45 @@ public class NubPointerType(NubType baseType) : NubType } } -public class NubArrayType(NubType baseType) : NubType +public class NubArrayType(NubType elementType) : NubType { - public NubType BaseType { get; } = baseType; + public NubType ElementType { get; } = elementType; public override bool Equals(object? obj) { if (obj is NubArrayType other) { - return BaseType.Equals(other.BaseType); + return ElementType.Equals(other.ElementType); } return false; } public override int GetHashCode() { - return HashCode.Combine(BaseType); + return HashCode.Combine(ElementType); } public override string ToString() { - return "[]" + BaseType; + return "[]" + ElementType; + } +} + +public class NubFixedArrayType(NubType elementType, int capacity) : NubType +{ + public NubType ElementType { get; } = elementType; + public int Capacity { get; } = capacity; + + public override string ToString() => $"[{Capacity}]{ElementType}"; + + public override bool Equals(object? obj) + { + return obj is NubFixedArrayType other && ElementType.Equals(other.ElementType) && Capacity == other.Capacity; + } + + public override int GetHashCode() + { + return HashCode.Combine(ElementType, Capacity); } } diff --git a/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs b/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs index 1f919d8..7d88590 100644 --- a/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs +++ b/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using Nub.Lang.Diagnostics; using Nub.Lang.Frontend.Parsing; using Nub.Lang.Frontend.Parsing.Definitions; @@ -245,6 +246,11 @@ public class TypeChecker return nubPointerType.BaseType; } + private NubType TypeCheckFixedInitializerArray(FixedArrayInitializerNode fixedArrayInitializer) + { + return new NubFixedArrayType(fixedArrayInitializer.ElementType, fixedArrayInitializer.Capacity); + } + private NubType? TypeCheckFuncCall(FuncCallNode funcCall, Node node) { List parameterTypes = []; @@ -375,11 +381,12 @@ public class TypeChecker BinaryExpressionNode binaryExpr => TypeCheckBinaryExpression(binaryExpr), CastNode cast => TypeCheckCast(cast), DereferenceNode dereference => TypeCheckDereference(dereference), + FixedArrayInitializerNode fixedArray => TypeCheckFixedInitializerArray(fixedArray), FuncCallNode funcCallExpr => TypeCheckFuncCall(funcCallExpr, funcCallExpr), StructInitializerNode structInit => TypeCheckStructInitializer(structInit), UnaryExpressionNode unaryExpression => TypeCheckUnaryExpression(unaryExpression), MemberAccessNode memberAccess => TypeCheckMemberAccess(memberAccess), - _ => ReportUnsupportedExpression(expression) + _ => throw new UnreachableException() }; if (resultType != null) @@ -390,30 +397,28 @@ public class TypeChecker return resultType; } - private NubType? ReportUnsupportedExpression(ExpressionNode expression) - { - ReportError($"Unsupported expression type: {expression.GetType().Name}", expression); - return null; - } - private NubType? TypeCheckArrayIndex(ArrayIndexAccessNode arrayIndexAccess) { var expressionType = TypeCheckExpression(arrayIndexAccess.Array); if (expressionType == null) return null; - - if (expressionType is not NubArrayType arrayType) - { - ReportError($"Cannot access index of non-array type {expressionType}", arrayIndexAccess.Array); - return null; - } - var indexType = TypeCheckExpression(arrayIndexAccess.Index); if (indexType != null && !IsInteger(indexType)) { ReportError("Array index type must be an integer", arrayIndexAccess.Index); } + + if (expressionType is NubArrayType arrayType) + { + return arrayType.ElementType; + } + + if (expressionType is NubFixedArrayType fixedArrayType) + { + return fixedArrayType.ElementType; + } - return arrayType.BaseType; + ReportError($"Cannot access index of non-array type {expressionType}", arrayIndexAccess.Array); + return null; } private NubType TypeCheckArrayInitializer(ArrayInitializerNode arrayInitializer) diff --git a/src/runtime/core/syscall.asm b/src/runtime/core/syscall.asm new file mode 100644 index 0000000..2ae7c93 --- /dev/null +++ b/src/runtime/core/syscall.asm @@ -0,0 +1,9 @@ +section .text +global core_syscall +core_syscall: + mov rax, rdi + mov rdi, rsi + mov rsi, rdx + mov r10, rcx + syscall + ret \ No newline at end of file diff --git a/src/runtime/runtime.asm b/src/runtime/runtime.asm index 1562905..748cfc5 100644 --- a/src/runtime/runtime.asm +++ b/src/runtime/runtime.asm @@ -9,6 +9,9 @@ _start: mov rax, 60 syscall +; String comparison function null-terminated strings +; Arguments: rdi = lhs (*char), rsi = rhs (*char) +; Returns: 1 if equal, else 0 global nub_strcmp nub_strcmp: xor rdx, rdx @@ -28,6 +31,9 @@ nub_strcmp: mov rax, 1 ret +; Panic function with message +; Arguments: rdi = message (*char), rsi = message length (long) +; Remarks: exits the program global nub_panic nub_panic: mov rdx, rsi @@ -39,73 +45,50 @@ nub_panic: mov rdi, 101 syscall -; TODO: This is ai-generated. Should be re-implemented in the future +; Memory set function +; Arguments: rdi = destination pointer, rsi = value (byte), rdx = count +; Returns: rdi (original destination pointer) global nub_memset nub_memset: - ; Save original destination for return value - mov rax, rdi + push rdi ; Save original destination for return value + mov rcx, rdx ; Load count into counter register + mov al, sil ; Move byte value to al (lower 8 bits of rsi) - ; Handle zero length - test rdx, rdx + ; Handle zero count case + test rcx, rcx jz .done - ; For small sizes, use simple byte-by-byte loop - cmp rdx, 16 - jb .byte_loop - - ; Prepare value for bulk setting - ; Replicate the byte across all 8 bytes of rsi - and rsi, 0xFF ; Ensure only low byte is used - mov rcx, rsi ; rcx = byte value - shl rsi, 8 - or rsi, rcx ; rsi = byte | (byte << 8) - mov rcx, rsi - shl rsi, 16 - or rsi, rcx ; rsi = 4 copies of byte - mov rcx, rsi - shl rsi, 32 - or rsi, rcx ; rsi = 8 copies of byte - - ; Align to 8-byte boundary if needed - mov rcx, rdi - and rcx, 7 ; rcx = bytes until 8-byte aligned - jz .aligned - - ; Fill bytes until aligned - neg rcx - add rcx, 8 ; rcx = bytes to fill for alignment - cmp rcx, rdx - jbe .align_loop - mov rcx, rdx ; Don't go past end -.align_loop: - mov [rdi], sil - inc rdi - dec rdx - dec rcx - jnz .align_loop - -.aligned: - ; Fill 8 bytes at a time - mov rcx, rdx - shr rcx, 3 ; rcx = number of 8-byte chunks - jz .remainder -.quad_loop: - mov [rdi], rsi - add rdi, 8 - dec rcx - jnz .quad_loop - - ; Handle remainder bytes - and rdx, 7 ; rdx = remaining bytes -.remainder: - test rdx, rdx - jz .done - -.byte_loop: - mov [rdi], sil - inc rdi - dec rdx - jnz .byte_loop +.loop: + mov [rdi], al ; Store byte at current position + inc rdi ; Move to next byte + dec rcx ; Decrement counter + jnz .loop ; Continue if counter not zero .done: - ret \ No newline at end of file + pop rax ; Return original destination pointer + ret + +; Memory copy function +; Arguments: rdi = destination, rsi = source, rdx = count +; Returns: rdi (original destination pointer) +global nub_memcpy +nub_memcpy: + push rdi ; Save original destination for return value + mov rcx, rdx ; Load count into counter register + + ; Handle zero count case + test rcx, rcx + jz .done + + ; Simple byte-by-byte copy (no overlap handling) +.loop: + mov al, [rsi] ; Load byte from source + mov [rdi], al ; Store byte to destination + inc rsi ; Move to next source byte + inc rdi ; Move to next destination byte + dec rcx ; Decrement counter + jnz .loop ; Continue if counter not zero + +.done: + pop rax ; Return original destination pointer + ret