uint16 NTYPE_MODULE = 0 uint16 NTYPE_EXPORT = 1 uint16 NTYPE_STRUCT = 2 uint16 NTYPE_TYPE = 3 uint16 NTYPE_ID = 4 uint16 NTYPE_BIN_OP = 5 uint16 NTYPE_PRE_OP = 6 uint16 NTYPE_POST_OP = 7 uint16 NTYPE_FUNCTION = 8 uint16 NTYPE_METHOD = 9 uint16 NTYPE_TLIST = 10 uint16 NTYPE_DLIST = 11 uint16 NTYPE_ELIST = 12 uint16 NTYPE_LITERAL = 13 uint16 NTYPE_KEY_TYPE = 14 uint16 NTYPE_ENUM = 15 uint16 NTYPE_ASM = 998 struct Node { uint16 _type, ~uint8 data, utils.Vector sub } /; method Node /; init (uint16 _type, ~uint8 data) self.data = data self._type = _type Node n self.sub.init(len n) ;/ /; end _delete(self.data) /; loop (uint i = 0; i < self.sub.count) [i++] ~Node cur = self.sub.get(i) cur`.end() ;/ self.sub.end() ;/ ;/ /; _ast_import(~utils.File fin, ~Node mod, ~Token first) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ~uint8 path = utils.unquote_str(tmp.data) utils.File _import = fin`.relative(path) _delete(path) path = _import.path.to_cstr('/') _printf("Importing ./\0") _printf(path) _printf("\n\0") _delete(path) _ast_file(~_import, mod) _import.end() ;/ /; _get_closing_delim(uint8 ch) [uint8] /; if (ch == '/' || ch == ';') return ';' ;; else if (ch == '(') return ')' ;; else if (ch == '{') return '}' ;; else if (ch == '[') return ']' ;/ return 0 ;/ /; _ast_type (~utils.File fin, ~Node mod, ~Token first) Node out out.init(NTYPE_TYPE, utils.strcpy("\0")) # Handle pointer and array types /; loop (first`.eq("~\0") == true || first`.eq("{\0") == true) Node pre pre.init(NTYPE_PRE_OP, first`.data) /; if (first`.eq("{\0") == true) first` = produce_next_token(fin, first`) /; if (first`._type == TTYPE_LITRL && is_numeric(first`.data`)) Node i i.init(NTYPE_LITERAL, first`.data) pre.sub.push(~i) ;; else if (first`.eq("}\0") == false) _printf("Expected integer for array type or '}':") _printf(" \0") print_token(first`) _printf("\n\0") ;; else Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;/ out.sub.push(~pre) first` = produce_next_token(fin, first`) ;/ /; if (first`._type !== TTYPE_KEYTP && first`._type !== TTYPE_USRWD) _printf("Expected key type or user type:") _printf(" \0") print_token(first`) _printf("\n\0") ;/ # Are we a void type? (Matters for getting params or ) bool vd = false /; if (first`.eq("void\0") == true) vd = true ;/ # Fully qualified type name /; if (first`._type == TTYPE_USRWD) /; loop (bool run = true; run == true) Node usr usr.init(NTYPE_ID, first`.data) first` = produce_next_token(fin, first`) out.sub.push(~usr) /; if (first`.eq(".\0") == true) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp /; if (first`._type !== TTYPE_USRWD) run = false _printf("Expected completion of user type:") _printf(" \0") print_token(tmp) _printf("\n\0") ;/ ;; else run = false ;/ ;/ ;; else Node tp tp.init(NTYPE_ID, first`.data) out.sub.push(~tp) first` = produce_next_token(fin, first`) ;/ # Generics or void call type /; if (first`._type == TTYPE_DELIM && first`.data` == '(') _ast_type_list(fin, ~out, first) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ # Void return type /; if (vd && first`._type == TTYPE_DELIM && first`.data` == '[') _ast_type_list(fin, ~out, first) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ # Reference /; if (first`.eq("`\0") == true) Node post post.init(NTYPE_PRE_OP, first`.data) out.sub.push(~post) first` = produce_next_token(fin, first`) ;/ mod`.sub.push(~out) ;/ /; _ast_decl (~utils.File fin, ~Node mod, ~Token first) ;/ /; _ast_decl_list (~utils.File fin, ~Node mod, ~Token first) ;/ /; _ast_expr (~utils.File fin, ~Node mod, ~Token first) ;/ /; _ast_maybe_expr_decl (~utils.File fin, ~Node mod, ~Token first) # Handle the case where it's ambiguous whether we have a type definition or an expression ;/ /; _ast_expr_list(~utils.File fin, ~Node mod, ~Token first) uint8 closing = _get_closing_delim(first`.data`) Node expr_list expr_list.init(NTYPE_ELIST, first`.data) first` = produce_next_token(fin, first`) bool run = true /; if (first`._type == TTYPE_DELIM && first`.data` == closing) run = false ;; else _ast_maybe_expr_decl(fin, ~expr_list, first) ;/ /; loop (run == true && first`._type !== TTYPE_ERR) /; if (first`._type == TTYPE_DELIM && first`.data` == closing) run = false ;; else if (first`._type == TTYPE_SEP && first`.eq(";\0")) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp _ast_maybe_expr_decl(fin, ~expr_list, first) ;; else _printf("Unexpected token when parsing a list of types:\n\0") _printf(" \0") print_token(first`) _printf("\n\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;/ mod`.sub.push(~expr_list) ;/ /; _ast_type_list (~utils.File fin, ~Node mod, ~Token first) uint8 closing = _get_closing_delim(first`.data`) Node type_list type_list.init(NTYPE_TLIST, first`.data) Token tmp = produce_next_token(fin, first`) first` = tmp bool run = true /; if (first`._type == TTYPE_DELIM && first`.data` == closing) run = false ;; else if (first`._type == TTYPE_KEYTP || first`._type == TTYPE_USRWD || first`.eq("~\0") == true) _ast_type(fin, ~type_list, first) ;; else _printf("Expected type or closing of type list:\n\0") _printf(" \0") print_token(tmp) _printf("\n\0") ;/ /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (first`._type == TTYPE_DELIM && first`.data` == closing) run = false ;; else if (first`._type == TTYPE_SEP && first`.eq(",\0")) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp /; if (first`._type == TTYPE_KEYTP || first`._type == TTYPE_USRWD || first`.eq("~\0") == true) _ast_type(fin, ~type_list, first) ;/ ;; else _printf("Expected comma ',' and then type:\n\0") _printf(" \0") print_token(tmp) _printf("\n\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;/ mod`.sub.push(~type_list) ;/ /; _ast_struct (~utils.File fin, ~Node mod, ~Token first) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp /; if (tmp._type !== TTYPE_USRWD) _printf("Unexpected token after struct keyword:\n\0") _printf(" \0") print_token(tmp) _printf("\n\0") return ;/ Node out out.init(NTYPE_STRUCT, tmp.data) first` = produce_next_token(fin, tmp) _ast_decl_list(fin, out, first) mod`.sub.push(~out) ;/ /; _ast_method (~utils.File fin, ~Node mod, ~Token first) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp /; if (tmp._type !== TTYPE_USRWD) _printf("Expected a user-defined type after 'method':\n\0") _printf(" \0") print_token(tmp) _printf("\n\0") return ;/ Node out out.init(NTYPE_METHOD, tmp.data) tmp = produce_next_token(fin, tmp) first` = tmp /; loop (first`._type !== TTYPE_ERR && first`.eq(";;\0") == false && first`.eq(";/\0") == false) /; if (first`.eq("/;\0") == true) tmp = produce_next_token(fin, tmp) first`.end() first` = tmp _ast_function(fin, ~out, first) /; loop (first`.eq(";;") == true) tmp = produce_next_token(fin, tmp) first`.end() first` = tmp _ast_function(fin, ~out, first) ;/ ;; else _printf("Expected only function blocks in method block:\n\0") _printf(" \0") print_token(tmp) _printf("\n\0") tmp = produce_next_token(fin, tmp) first`.end() first` = tmp ;/ ;/ mod`.sub.push(~out) ;/ /; _ast_asm(~utils.File fin, ~Node mod, ~Token first) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp /; if (tmp._type !== TTYPE_LITRL || tmp.data{0} !== '"') _printf("Expected string token after 'asm' keyword:\n\0") _printf(" \0") print_token(tmp) _printf("\n\0") return ;/ Node out out.init(NTYPE_ASM, utils.unquote_str(tmp.data)) mod`.sub.push(~out) first` = produce_next_token(fin, tmp) tmp.end() ;/ /; _ast_function (~utils.File fin, ~Node mod, ~Token first) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp /; if (tmp._type !== TTYPE_USRWD) _printf("Expected function name (Compiler bug, not user program issue):\n\0") _printf(" \0") print_token(tmp) _printf("\n\0") return ;/ uint line = first`.line /; loop (line == first`.line) ;/ ;/ /; _ast_block (~utils.File fin, ~Node mod, ~Token first) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp /; if (tmp._type == TTYPE_USRWD) _ast_function(fin, mod, first) ;; else if (tmp.eq("method\0") == true) _ast_method(fin, mod, first) ;; else if (tmp.eq("module\0") == true || tmp.eq("export\0") == true) _ast_module(fin, mod, first) ;; else _printf("Expected function definition, 'method', or 'module' after block opening (root of file or module):\n\0") _printf(" \0") print_token(tmp) _printf("\n\0") ;/ /; if (first`.eq(";;\0") == true) _ast_block(fin, mod, first) ;; else tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;/ /; _ast_module (~utils.File fin, ~Node mod, ~Token first) Token tmp uint16 _type = NTYPE_MODULE /; if (first`.eq("export\0")) _type = NTYPE_EXPORT tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ tmp = produce_next_token(fin, first`) first`.end() first` = tmp /; if (tmp._type !== TTYPE_USRWD) _printf("Expected module name: \0") print_token(tmp) return ;/ Node out out.init(_type, tmp.data) tmp = produce_next_token(fin, first`) first` = tmp /; loop(first`._type !== TTYPE_ERR && first`.eq(";;\0") == false && first`.eq(";/\0") == false) /; if (first`.eq("import\0") == true) _ast_import(fin, ~out, first) ;; else if (first`.eq("struct\0") == true) _ast_struct(fin, ~out, first) ;; else if (first`.eq("asm\0") == true) _ast_asm(fin, ~out, first) ;; else if (first`.eq("/;\0") == true) _ast_block(fin, ~out, first) ;; else if (first`._type == TTYPE_KEYTP || first`._type == TTYPE_USRWD || first`.eq("~\0") == true) _ast_decl(fin, ~out, first) ;; else tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;/ mod`.sub.push(~out) ;/ /; _ast_file (~utils.File fin, ~Node mod) fin`.open() Token first = produce_first_token(fin) /; loop (first._type !== TTYPE_ERR) /; if (first.eq("import\0") == true) _ast_import(fin, mod, ~first) ;; else if (first.eq("struct\0") == true) _ast_struct(fin, mod, ~first) ;; else if (first.eq("asm\0") == true) _ast_asm(fin, mod, ~first) ;; else if (first.eq("/;\0") == true) _ast_block(fin, mod, ~first) ;; else if (first._type == TTYPE_KEYTP || first._type == TTYPE_USRWD || first.eq("~\0") == true) _ast_decl(fin, mod, ~first) ;; else Token tmp = produce_next_token(fin, first) first.end() first = tmp ;/ ;/ fin`.close() ;/ /; generate_ast (~utils.File fin) [Node] Node out utils.Vector v v.init(1) out.init(NTYPE_MODULE, v.as_cstr()) _ast_file(fin, ~out) return out ;/ # # Print out the AST from a specific node # /; print_node_type (~Node n) /; if (n`._type == NTYPE_MODULE) _printf("Mod\0") ;; else if (n`._type == NTYPE_EXPORT) _printf("Exported Module\0") ;; else if (n`._type == NTYPE_STRUCT) _printf("Struct\0") ;; else if (n`._type == NTYPE_ID) _printf("ID\0") ;; else if (n`._type == NTYPE_BIN_OP) _printf("Binary OP\0") ;; else if (n`._type == NTYPE_PRE_OP) _printf("Pre OP\0") ;; else if (n`._type == NTYPE_POST_OP) _printf("Post OP\0") ;; else if (n`._type == NTYPE_FUNCTION) _printf("Function\0") ;; else if (n`._type == NTYPE_METHOD) _printf("Method\0") ;; else if (n`._type == NTYPE_ASM) _printf("ASM\0") ;/ ;/ /; print_node_head (~Node n) _printf("{ NODE_TYPE: \0") print_node_type(n) _printf(", DATA: \0") _printf(n`.data) _printf("\n\0") ;/ /; print_ast_rec(~Node n, uint depth) /; loop (int i = 0; i < depth) [i++] _printf(" \0") ;/ print_node_head(n) /; loop (uint i = 0; i < n`.sub.count) [i++] ~Node s = n`.sub.get(i) print_ast_rec(s, depth + 1) ;/ /; loop (int i = 0; i < depth) [i++] _printf(" \0") ;/ _printf("}\n\0") ;/ /; print_ast (~Node n) print_ast_rec(n, 0) ;/