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_SLIST = 13 uint16 NTYPE_LITERAL = 14 # uint16 NTYPE_KEY_TYPE = 14 # Unused uint16 NTYPE_ENUM = 15 uint16 NTYPE_DECL = 16 uint16 NTYPE_VLIST = 17 uint16 NTYPE_VALUE = 18 uint16 NTYPE_CAST = 19 uint16 NTYPE_FLOW_CONTROL = 20 uint16 NTYPE_IF_BLOCK = 21 uint16 NTYPE_ELIF_BLOCK = 22 uint16 NTYPE_ELSE_BLOCK = 23 uint16 NTYPE_LOOP_BLOCK = 24 uint16 NTYPE_ASM = 998 uint16 NTYPE_EMPTY = 999 struct Node { uint16 _type, ~uint8 data, utils.Vector sub, ~Node parent } /; method Node /; init (uint16 _type, ~uint8 data) self.data = data self._type = _type self.parent = NULL Node n self.sub.init(len n) self.parent = NULL ;/ /; eq (~uint8 cstr) [bool] /; if (utils.strcmp(self.data, cstr) == true) return true ;/ return false ;/ /; end _delete(self.data) /; loop (uint i = 0; i < self.sub.count) [i++] ~Node cur = self.sub.get(i) cur`.end() ;/ self.sub.end() ;/ /; update_children /; loop (int i = 0; i < self.sub.count) [i++] ~Node cur = self.sub.get(i) cur`.parent = ~self ;/ ;/ /; add_child(~Node n) [~Node] n`.parent = ~self ~int chk = self.sub.data self.sub.push(n) ~int cmp = self.sub.data /; if (chk != cmp) # Only update children when the reallocation # returns a new memory block /; loop (int i = 0; i < self.sub.count) [i++] n = self.sub.get(i) n`.update_children() ;/ ;; else n = self.sub.get(self.sub.count - 1) n`.update_children() ;/ return n ;/ ;/ /; _get_closing_delim(uint8 ch) [uint8] /; if (ch == '/' || ch == ';') return ';' ;; else if (ch == '(') return ')' ;; else if (ch == '[') return ']' ;; else if (ch == '{') return '}' ;/ return 0 ;/ /; _is_closing(~Token tok) [bool] /; if (tok`._type !== TTYPE_DELIM) return false ;/ uint8 ch = tok`.data` /; if (ch == ';' || ch == '}' || ch == ']' || ch == ')') return true ;/ return false ;/ /; _advance_check(~utils.File fin, ~Token tok, ~uint8 eq) [bool] /; if (tok`._type !== TTYPE_ERR && tok`.eq(eq) == true) Token tmp = produce_next_token(fin, tok`) tok`.end() tok` = tmp return true ;/ return false ;/ int MAX_ERR_SHOW = 15 int errors_shown = 0 /; _ast_print_err (~utils.File fin, ~Token tok, ~uint8 msg) /; if (errors_shown !< MAX_ERR_SHOW) return ;/ errors_shown = errors_shown + 1 _printf(msg) _printf(":\n\0") _printf(" File: \0") ~uint8 p = fin`.path.to_cstr('/') _printf(p) _delete(p) _printf("\n At: \0") print_token(tok`) _printf("\n\0") /; if (errors_shown == MAX_ERR_SHOW) _printf("\nToo many errors to print, other errors will be suppressed\n\0") ;/ ;/ /; _ast_block_pass(~utils.File fin, ~Token first) /; loop (int deep = 1; deep > 0 && first`._type !== TTYPE_ERR) /; if (first`.eq(";/\0") == true) deep = deep - 1 ;; else if (first`.eq("/;\0") == true) deep = deep + 1 ;; else if (first`.eq(";;\0") == true && deep == 1) deep = deep - 1 ;/ /; if (deep > 0) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;/ ;/ # AST values /; _op_prefix(~Token op) [bool] int l = utils.strlen(op`.data) /; if (op`._type !== TTYPE_AUG) return false ;/ /; if (op`.eq("len\0") == true || op`.eq("--\0") == true || op`.eq("++\0") == true) return true ;/ /; if (l !== 1) return false ;/ /; if (op`.data` == '-' || op`.data` == '!' || op`.data` == '~') return true ;/ return false ;/ /; _op_postfix(~Token op) [bool] /; if (op`.eq("`\0") == true || op`.eq("++\0") == true || op`.eq("--\0") == true) return true ;/ return false ;/ /; _op_bin(~Token op) [bool] /; if (op`.eq("-\0") == true) return true ;/ /; if (_op_prefix(op) == true || _op_postfix(op) == true) return false ;/ return true ;/ /; _op_order(~uint8 op) [int] int l = utils.strlen(op) /; if (l == 1) uint8 ch = op` /; if (ch == '`') return 0 ;; else if (ch == '.') return 1 ;; else if (ch == '~') return 2 ;; else if (ch == '*' || ch == '/' || ch == '%') return 6 ;; else if (ch == '+' || ch == '-') return 7 ;; else if (ch == '!' || ch == '&' || ch == '|' || ch == '^') return 8 ;; else if (ch == '<' || ch == '>') return 9 ;; else if (ch == '=') return 11 ;/ ;; else if (l == 2) /; if (utils.strcmp(op, "is\0")) return 2 ;/ /; if (op{0} == op{1}) uint8 ch = op` /; if (ch == '+' || ch == '-') return 3 ;; else if (ch == '<' || ch == '>') return 4 ;; else if (ch == '=') return 9 ;/ return 10 ;/ /; if (op{1} == '<' || op{1} == '>') return 9 ;; else if (op{1} == '=') return 11 ;; else if (op{0} == '!') return 8 ;/ ;; else if (l == 3) /; if (utils.strcmp(op, "len\0") == true) return 5 ;; else if (op{1} == '=') return 9 ;/ return 10 ;/ _printf("[FATAL] [CMPERR] _op_order: Augment not implemented in ordering \0") _print_num("'%s'\n\0", op) return 999 ;/ /; _astv_pre_id (~utils.File fin, ~Node cur, ~Token first) [~Node] /; loop (first`._type == TTYPE_AUG) /; if (_op_prefix(first) == false) _ast_print_err(fin, first, "Only certain augments (-, !, ~, --, ++, len) can be used as prefixes for bare values\0") return cur ;/ Node pre pre.init(NTYPE_PRE_OP, first`.data) cur = cur`.add_child(~pre) first` = produce_next_token(fin, first`) ;/ return cur ;/ /; _astv_cast (~utils.File fin, ~Node mod, ~Token first) [int] int out = first`.line /; if (first`.eq("[\0")) Node cast cast.init(NTYPE_CAST, utils.strcpy("\0")) out = _ast_list_type(fin, ~cast, first) ~Node tmp = mod`.sub.get(mod`.sub.count - 1) cast.add_child(tmp) mod`.sub.pop() mod`.add_child(~cast) ;/ return out ;/ /; _astv_post_id (~utils.File fin, ~Node mod, ~Token first, bool lnok) [int] int ln = first`.line /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (ln !== first`.line && lnok == false) run = false ;; else if (_op_postfix(first) == true) Node post post.init(NTYPE_POST_OP, first`.data) mod`.add_child(~post) first` = produce_next_token(fin, first`) ;; else if (first`.eq("(\0") == true) ln = _ast_list_value(fin, mod, first) /; if (first`.eq("[\0") == true && (ln == first`.line || lnok == true)) ln = _ast_list_value(fin, mod, first) run = false ;/ ;; else if (first`.eq("{\0") == true) Node ind ind.init(NTYPE_POST_OP, first`.data) first` = produce_next_token(fin, first`) /; if (_ast_value(fin, ~ind, first, true) == false) _ast_print_err(fin, first, "Expected value for index operation after '{'\0") ;/ mod`.add_child(~ind) ln = first`.line /; if (_advance_check(fin, first, "}\0") == false) _ast_print_err(fin, first, "Expected '}' to show the end of an index operation after the value\0") run = false ;/ ;; else run = false ;/ ;/ return ln ;/ /; _ast_value_bare(~utils.File fin, ~Node mod, ~Token first, bool lnok) [bool] ~Node cur = mod cur = _astv_pre_id(fin, cur, first) int ln = first`.line # Pre-flight check /; if (first`.eq("{\0") == true) ln = _ast_list_value(fin, cur, first) ;; else if (_advance_check(fin, first, "(\0") == true) _ast_value(fin, cur, first, true) ln = first`.line /; if (_advance_check(fin, first, ")\0") == false) _ast_print_err(fin, first, "Expected closing ')' for singlet\0") return false ;/ /; if (ln == first`.line || lnok == true) ln = _astv_cast(fin, cur, first) ~Node tmp = cur`.sub.get(cur`.sub.count - 1) ;/ ;; else if (first`._type == TTYPE_USRWD) Node val val.init(NTYPE_ID, first`.data) first` = produce_next_token(fin, first`) cur`.add_child(~val) ;; else if (first`._type == TTYPE_LITRL) Node val val.init(NTYPE_LITERAL, first`.data) first` = produce_next_token(fin, first`) cur`.add_child(~val) ;; else _ast_print_err(fin, first, "Expected compound, parenthetical, literal, or identifier for bare value\0") return false ;/ /; if (ln == first`.line || lnok == true) ln = _astv_post_id(fin, cur`.sub.get(cur`.sub.count - 1), first, lnok) ;; else return true ;/ bool run = ln == first`.line # Methods and members /; loop (; run == true && _advance_check(fin, first, ".\0") == true) /; if (first`._type !== TTYPE_USRWD) _ast_print_err(fin, first, "Expected method/member name after '.'\0") return false ;/ ~Node repl = cur`.sub.get(cur`.sub.count - 1) Node dot dot.init(NTYPE_BIN_OP, utils.strcpy(".\0")) dot.add_child(repl) Node val val.init(NTYPE_ID, first`.data) int ln = first`.line first` = produce_next_token(fin, first`) /; if (first`.line !== ln && lnok == false) run = false ;; else ln = _astv_post_id(fin, ~val, first, lnok) ;/ dot.add_child(~val) cur`.sub.pop() cur = cur`.add_child(~dot) ;/ return true ;/ /; _assoc_right(~uint8 op) [bool] int order = _op_order(op) /; if (order == 11) return true ;/ return false ;/ # op - operator to compare against # i - op order of inserting op /; _assoc (~uint8 op, int i) [bool] int j = _op_order(op) /; if (_assoc_right(op) && i == j) return false ;/ return i !< j ;/ # Needs to be re-done to respect left and right associativity rules /; _ast_value (~utils.File fin, ~Node mod, ~Token first, bool lnok) [bool] Node val val.init(NTYPE_VALUE, utils.strcpy("\0")) ~Node cur = ~val bool run = _ast_value_bare(fin, cur, first, lnok) bool valid = run /; loop (run == true && first`._type !== TTYPE_ERR) /; if (first`._type == TTYPE_SEP || _is_closing(first) == true) run = false ;; else if (first`.eq(".\0") == true) run = false valid = false ;; else if (first`._type == TTYPE_AUG && _op_bin(first) == true) Node bin bin.init(NTYPE_BIN_OP, first`.data) int i = _op_order(first`.data) bool gt = false /; if (cur`._type == NTYPE_BIN_OP) gt = _assoc(cur`.data, i) ;/ # Start from the top and work our way down /; loop (gt == true) cur = cur`.parent /; if (cur`._type == NTYPE_BIN_OP) gt = _assoc(cur`.data, i) ;; else gt = false ;/ ;/ ~Node rhs = cur`.sub.get(cur`.sub.count - 1) bin.add_child(rhs) cur`.sub.pop() cur = cur`.add_child(~bin) first` = produce_next_token(fin, first`) /; if (utils.strcmp(bin.data, "is\0")) _ast_type(fin, cur, first) ;; else run = _ast_value_bare(fin, cur, first, lnok) valid = run ;/ ;; else run = false ;/ ;/ mod`.add_child(~val) return valid ;/ /; _ast_keyword_expr (~utils.File fin, ~Node mod, ~Token first) int ln = first`.line /; if (first`.eq("return\0") == true || first`.eq("continue\0") == true || first`.eq("break\0") == true) Node ret ret.init(NTYPE_FLOW_CONTROL, first`.data) first` = produce_next_token(fin, first`) /; if (first`.line == ln && _is_closing(first) == false && first`._type !== TTYPE_ERR) _ast_value(fin, ~ret, first, false) ;/ mod`.add_child(~ret) return ;; else _ast_print_err(fin, first, "Unsupported keyword statement\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;/ # AST types /; _type_helper_pre (~utils.File fin, ~Node mod, ~Token first) /; loop (bool run = true; first`._type !== TTYPE_ERR && run == true) /; if (first`._type == TTYPE_AUG && first`.eq("~\0") == true) # Pointer Node ptr ptr.init(NTYPE_PRE_OP, first`.data) mod`.add_child(~ptr) first` = produce_next_token(fin, first`) ;; else if (first`._type == TTYPE_DELIM && first`.eq("{\0") == true) # Array Node arr arr.init(NTYPE_PRE_OP, first`.data) first` = produce_next_token(fin, first`) /; if (first`._type == TTYPE_LITRL && is_numeric(first`.data`) == true) Node num num.init(NTYPE_LITERAL, first`.data) arr.add_child(~num) first` = produce_next_token(fin, first`) /; if (first`.eq("}\0") == true) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;; else _ast_print_err(fin, first, "Expected closing '}' after integer in type declaration\0") run = false ;/ ;; else if (first`.eq("}\0") == true) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;; else _ast_print_err(fin, first, "Expected integer or '}' to define either a fixed sized array or pointer to unknown sized array\0") run = false ;/ mod`.add_child(~arr) ;; else run = false ;/ ;/ ;/ /; _type_helper_func (~utils.File fin, ~Node mod, ~Token first) /; if (first`.eq("(\0") == true) _ast_list_type(fin, mod, first) ;/ /; if (first`.eq("[\0") == true) _ast_list_type(fin, mod, first) ;/ ;/ /; _type_helper_usertype (~utils.File fin, ~Node mod, ~Token first) /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (first`._type == TTYPE_USRWD) Node utp utp.init(NTYPE_ID, first`.data) first` = produce_next_token(fin, first`) mod`.add_child(~utp) /; if (first`._type !== TTYPE_AUG || first`.eq(".\0") == false) run = false ;; else Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;; else _ast_print_err(fin, first, "Expected identifier in fully qualified type chain\0") run = false ;/ ;/ /; if (first`._type == TTYPE_DELIM && first`.eq("(\0") == true) _ast_list_type(fin, mod, first) ;/ ;/ /; _ast_type (~utils.File fin, ~Node mod, ~Token first) Node typ typ.init(NTYPE_TYPE, utils.strcpy("\0")) # Prefix values (~, {}, {#}) _type_helper_pre(fin, ~typ, first) # Check to see if this is a function pointer type /; if (first`.eq("void\0") == true) Node ktp ktp.init(NTYPE_ID, first`.data) typ.add_child(~ktp) first` = produce_next_token(fin, first`) _type_helper_func(fin, ~typ, first) mod`.add_child(~typ) return ;/ # user type or keytype /; if (first`._type == TTYPE_USRWD) _type_helper_usertype(fin, ~typ, first) ;; else if (first`._type == TTYPE_KEYTP) Node ktp ktp.init(NTYPE_ID, first`.data) typ.add_child(~ktp) first` = produce_next_token(fin, first`) ;; else _ast_print_err(fin, first, "Expected keytype or usertype when parsing type\0") mod`.add_child(~typ) return ;/ # The ol' reference /; if (first`.eq("`\0")) Node post post.init(NTYPE_POST_OP, first`.data) typ.add_child(~post) first` = produce_next_token(fin, first`) ;/ mod`.add_child(~typ) ;/ # AST lists /; _ast_list_value (~utils.File fin, ~Node mod, ~Token first) [int] Node list list.init(NTYPE_VLIST, first`.data) uint8 end = _get_closing_delim(first`.data`) first` = produce_next_token(fin, first`) /; loop (first`._type !== TTYPE_ERR && first`.data` !== end) _ast_value(fin, ~list, first, true) /; if (_advance_check(fin, first, ",\0") == false && (first`._type !== TTYPE_DELIM || first`.data` !== end)) _ast_print_err(fin, first, "Expected ',' to continue the value list or a closing delimiter\0") mod`.add_child(~list) return first`.line ;/ ;/ mod`.add_child(~list) int ln = first`.line Token next = produce_next_token(fin, first`) first`.end() first` = next return ln ;/ /; _maybe_helper_decl (~utils.File fin, ~Node mod, ~Token first) # either a continuation of prev type or a new type then an id Token next = produce_next_token(fin, first`) /; if (next._type !== TTYPE_ERR && next.eq(",\0") || _is_closing(~next) == true) # Another id Node id id.init(NTYPE_ID, first`.data) mod`.add_child(~id) first` = next return ;/ # have to parse as a type Node tp tp.init(NTYPE_TYPE, utils.strcpy("\0")) Node utmp utmp.init(NTYPE_ID, first`.data) tp.add_child(~utmp) first` = next bool run = true /; if (first`._type !== TTYPE_AUG || first`.eq(".\0") == false) run = false ;; else next = produce_next_token(fin, first`) first`.end() first` = next ;/ # Adapted from _type_helper_usertype /; loop (run == true && first`._type !== TTYPE_ERR) /; if (first`._type == TTYPE_USRWD) Node utp utp.init(NTYPE_ID, first`.data) first` = produce_next_token(fin, first`) tp.add_child(~utp) /; if (first`._type !== TTYPE_AUG || first`.eq(".\0") == false) run = false ;; else next = produce_next_token(fin, first`) first`.end() first` = next ;/ ;; else _ast_print_err(fin, first, "Expected identifier in fully qualified type chain\0") run = false ;/ ;/ /; if (first`._type == TTYPE_DELIM && first`.eq("(\0") == true) _ast_list_type(fin, ~tp, first) ;/ mod`.add_child(~tp) /; if (first`._type !== TTYPE_USRWD) _ast_print_err(fin, first, "Expected identifier after user type in type list\0") return ;/ Node id id.init(NTYPE_ID, first`.data) mod`.add_child(~id) first` = produce_next_token(fin, first`) ;/ /; _ast_list_decl (~utils.File fin, ~Node mod, ~Token first) [int] Node list list.init(NTYPE_DLIST, first`.data) uint8 end = _get_closing_delim(first`.data`) first` = produce_next_token(fin, first`) bool seen = false /; loop (first`._type !== TTYPE_ERR && first`.data` !== end) /; if (seen == false || first`._type ==TTYPE_KEYTP || first`.eq("~\0") == true || first`.eq("{\0") == true) _ast_type(fin, ~list, first) /; if (first`._type !== TTYPE_USRWD) /; if (seen == false) _ast_print_err(fin, first, "Expected type then identifier as first items in declaration list\0") ;; else _ast_print_err(fin, first, "Expected identifier after type in params/struct def\0") ;/ mod`.add_child(~list) return first`.line ;/ seen = true Node id id.init(NTYPE_ID, first`.data) list.add_child(~id) first` = produce_next_token(fin, first`) ;; else if (first`._type == TTYPE_USRWD) _maybe_helper_decl(fin, ~list, first) ;; else _ast_print_err(fin, first, "Expected type or parameter name in declaration list\0") mod`.add_child(~list) return first`.line ;/ /; if (_advance_check(fin, first, ",\0") == false && _is_closing(first) == false) _ast_print_err(fin, first, "Expected ',' to continue the declaration list or a closing delimiter\0") mod`.add_child(~list) return first`.line ;/ ;/ mod`.add_child(~list) int ln = first`.line Token next = produce_next_token(fin, first`) first`.end() first` = next return ln ;/ /; _ast_list_enum (~utils.File fin, ~Node mod, ~Token first) [int] Node list list.init(NTYPE_ELIST, first`.data) uint8 end = _get_closing_delim(first`.data`) first` = produce_next_token(fin, first`) int ln = first`.line /; loop (first`._type !== TTYPE_ERR && first`.data` !== end) /; if (first`._type == TTYPE_USRWD) ln = first`.line Node enum_id enum_id.init(NTYPE_ID, first`.data) first` = produce_next_token(fin, first`) /; if (_advance_check(fin, first, "=\0")) _ast_value(fin, ~enum_id, first, true) ;/ list.add_child(~enum_id) ;; else _ast_print_err(fin, first, "Expected identifier in body of enum declaration\0") mod`.add_child(~list) return ln ;/ /; if (first`.eq(",\0") == true) ln = first`.line ;/ /; if (_advance_check(fin, first, ",\0") == false && _is_closing(first) == false) _ast_print_err(fin, first, "Expected ',' to continue the type list or a closing delimiter\0") mod`.add_child(~list) return ln ;/ ;/ mod`.add_child(~list) ln = first`.line Token next = produce_next_token(fin, first`) first`.end() first` = next return ln ;/ /; _ast_list_type (~utils.File fin, ~Node mod, ~Token first) [int] Node list list.init(NTYPE_TLIST, first`.data) uint8 end = _get_closing_delim(first`.data`) first` = produce_next_token(fin, first`) int ln = first`.line /; loop (first`._type !== TTYPE_ERR && first`.data` !== end) /; if (first`._type == TTYPE_USRWD || first`._type == TTYPE_KEYTP || first`.eq("~\0") == true || first`.eq("{\0") == true) ln = first`.line _ast_type(fin, ~list, first) ;; else _ast_print_err(fin, first, "Expected type in type list\0") mod`.add_child(~list) return ln ;/ /; if (_advance_check(fin, first, ",\0") == false && _is_closing(first) == false) _ast_print_err(fin, first, "Expected ',' to continue the type list or a closing delimiter\0") mod`.add_child(~list) return ln ;/ ;/ mod`.add_child(~list) ln = first`.line Token next = produce_next_token(fin, first`) first`.end() first` = next return ln ;/ /; _ast_list_stmt (~utils.File fin, ~Node mod, ~Token first) Node list list.init(NTYPE_SLIST, first`.data) uint8 end = _get_closing_delim(first`.data`) first` = produce_next_token(fin, first`) int ln = first`.line /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR && first`.data` !== end) /; if (_advance_check(fin, first, "asm\0") == true) _ast_asm(fin, ~list, first) ;; else if (first`._type == TTYPE_KEYTP || first`.eq("{\0") == true) _ast_decl(fin, ~list, first) ;; else if (first`._type == TTYPE_USRWD || first`.eq("~\0") == true) _maybe_helper_fun(fin, ~list, first, true) ;; else if (first`._type == TTYPE_LITRL || _op_prefix(first)) _ast_value(fin, ~list, first, true) ;; else if (first`._type == TTYPE_KEYWD) _ast_keyword_expr(fin, ~list, first) ;; else if (first`.eq(";\0") == true) Node empty empty.init(NTYPE_EMPTY, utils.strcpy("\0")) list.add_child(~empty) ;; else _ast_print_err(fin, first, "Expected definition, expression, or ';' in statement list\0") run = false Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ /; if (_advance_check(fin, first, ";\0") == false) run = false ;/ ;/ mod`.add_child(~list) ln = first`.line /; if (first`._type !== TTYPE_DELIM || first`.data` !== end) _ast_print_err(fin, first, "Expected closing at end of statement list\0") ;; else Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ return ln ;/ # Method blocks /; _block_helper_method(~utils.File fin, ~Node mod, ~Token first) Token blf = first` first` = produce_next_token(fin, first`) /; loop (bool run = true; run == true) /; if (first`._type == TTYPE_USRWD) _ast_function(fin, mod, first) ;; else _ast_print_err(fin, first, "Expected function or operator overload in method block\0") ;/ _ast_block_pass(fin, first) /; if (_advance_check(fin, first, ";/\0") == true) /; if (first`.data` == ';') run = false ;; else if (_advance_check(fin, first, "/;\0") == false) _ast_print_err(fin, first, "Expected opening block in method block\0") ;/ ;; else if (_advance_check(fin, first, ";;\0") == false) _ast_print_err(fin, ~blf, "Could not find closing ;/ for function in method block\0") run = false ;/ ;/ blf.end() ;/ /; _ast_method (~utils.File fin, ~Node mod, ~Token first) Token blf = first` /; if (first`._type !== TTYPE_USRWD) _ast_print_err(fin, first, "Expected identifier of struct after 'method'\0") return ;/ Node mth mth.init(NTYPE_METHOD, first`.data) first` = produce_next_token(fin, first`) /; loop (bool run = true; run == true && first`._type == TTYPE_DELIM) /; if (first`.eq("/;\0") == true) _block_helper_method(fin, ~mth, first) ;; else /; if (first`.data` !== ';') _ast_print_err(fin, first, "Method block being skipped. Parsing will resume after the end\0") ;/ run = false ;/ ;/ _ast_block_pass(fin, first) /; if (first`.eq(";/\0") == false) _ast_print_err(fin, ~blf, "Could not find closing ;/ for method block\0") ;/ mod`.add_child(~mth) ;/ # function blocks /; _ast_flow (~utils.File fin, ~Node mod, ~Token first) uint16 block_type = NTYPE_IF_BLOCK /; if (_advance_check(fin, first, "else\0") == true) /; if (_advance_check(fin, first, "if\0") == true) block_type = NTYPE_ELIF_BLOCK ;; else block_type = NTYPE_ELSE_BLOCK ;/ ;; else if (_advance_check(fin, first, "loop\0") == true) block_type = NTYPE_LOOP_BLOCK ;; else Token tok = produce_next_token(fin, first`) first`.end() first` = tok ;/ Node out out.init(block_type, utils.strcpy("\0")) /; if (block_type != NTYPE_ELSE_BLOCK && first`.eq("(\0") == true) _ast_list_stmt(fin, ~out, first) ;/ /; if (block_type == NTYPE_LOOP_BLOCK && first`.eq("[\0") == true) _ast_list_stmt(fin, ~out, first) ;/ /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (first`._type == TTYPE_DELIM && first`.data` == ';') run = false ;; else if (_advance_check(fin, first, "asm\0") == true) _ast_asm(fin, ~out, first) ;; else if (first`.eq("/;\0") == true) _ast_fun_block(fin, ~out, first) ;; else if (first`._type == TTYPE_KEYTP || first`.eq("{\0") == true) _ast_decl(fin, ~out, first) ;; else if (first`._type == TTYPE_USRWD || first`.eq("~\0") == true) _maybe_helper_fun(fin, ~out, first, false) ;; else if (first`._type == TTYPE_LITRL || _op_prefix(first)) _ast_value(fin, ~out, first, false) ;; else if (first`._type == TTYPE_KEYWD) _ast_keyword_expr(fin, ~out, first) ;; else _ast_print_err(fin, first, "Expected definition, expression, or sub block in flow block\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;/ mod`.add_child(~out) ;/ /; _ast_fun_block (~utils.File fin, ~Node mod, ~Token first) Token blf = first` first` = produce_next_token(fin, first`) /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (first`.eq("if\0") == true || first`.eq("else\0") == true || first`.eq("loop\0") == true) _ast_flow(fin, mod, first) # ;; else if (first`._type == TTYPE_USRWD) # TODO: Functions in functions # _ast_function(fin, mod, first) ;; else _ast_print_err(fin, first, "Expected 'if', 'else', or 'loop' for function level block\0") ;/ run = _advance_check(fin, first, ";;\0") /; if (run == false && first`.eq(";/\0") == false) _ast_print_err(fin, first, "Block being skipped. Parsing will pick up after the end\0") ;/ ;/ _ast_block_pass(fin, first) /; if (_advance_check(fin, first`, ";/\0") == false) _ast_print_err(fin, ~blf, "Could not find closing ;/ for top block\0") ;/ blf.end() ;/ # The following code (mhf_post_list and mhf_post) # are a convoluted hellscape of terrible # design choices. Both functions may recursively call # the other, and both produce a multitude of different # output values based on what they think the AST should # be (sometimes based on the next token, sometimes not). # For instance, mhf_post tries to return NULL when it # thinks the next token means we are in a state where we # can parse a declaration (we have seen a valid type and # the next token is an identifier) but if we are calling # this function from mhf_post_list, we are inside a list, # making this an invalid next token in either the case # where we are parsing a declaraion OR the case where we # are parsing a value. It should blow up, so mhf_post_list # checks to see if it's null and returns whatever output # list it has created instead so something higher up the # chain (mhf_finish_value) can catch it and explode instead. # It's almost like an exception. Fuck me. # Otherwise, mhf_post will return whatever node the mhf_finish_value # should use as the node to start stitching together with binary operators # and values. Even worse, the node it should return may be a sub-node # FROM MHF_POST_LIST!!! # _mhf_post_list, however, should NEVER return NULL. In the case # where it suceeded in parsing a list of types, it will return # the passed in ~Node (which SHOULD be a type node), but otherwise, # it will return the node it was trying to generate when the failure # occurred. That's at least slightly fewer possible options, # but it is very important to remember that the token it ends on is # the end of the list, which allows checking whether the line # number of the next token is the same. If it's not, this WHOLE THING # was a FUNCTION CALL, and the ENTIRE FUCKING TREE NEEDS TO BE # RE-WORKED THROUGH THE TRANSFORM FUNCTION TO REPRESENT THAT. # Both functions try to compensate by checking the output # state of the other, and it creates a clusterfuck of strange # if statements and pointer logic that I wrote in an exremely # sleep deprived state. I'm just really hoping this # works. It will all probably get refactored later when # the standard library is fully flushed out and the compiler # is more mature. For now, may this warning be a sufficient # deterrant for the common programmar looking to refactor. # The only saving grace of this is I guess that it's O(n) # (Each loop iterates over tokens until it reaches an end state # and the tokens never back track. Plus I'm pretty sure the # transformer is O(n) in terms of the number of nodes in the # subtree.) # If you want to skip the most hellish spaghetti code I have ever # had the displesure of writing, just search for "maybe_helper_fun" # and have your editor of choice skip to that point. /; _mhf_post_list (~utils.File fin, ~Node mod, ~Token first) [~Node] Node out out.init(NTYPE_TLIST, first`.data) first` = produce_next_token(fin, first`) /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) Node _typ _typ.init(NTYPE_TYPE, utils.strcpy("\0")) _type_helper_pre(fin, ~_typ, first) /; if (first`._type == TTYPE_USRWD || first`._type == TTYPE_KEYTP) # Try to keep parsing as a type, if we error out we # will return whatever post returns ~Node cur = _mhf_post(fin, ~_typ, first, true) /; if (cur == ~_typ && first`.eq(",\0") == true) # Keep going Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;; else if (cur == ~_typ && first`.eq(")\0") == true) # Stop here, reached end of list run = false ;; else # Some error occurred, mhf_transform will # preserve lists so we return the list we were # creating. # mhf_finish_value can find the last valid parse # before the error occured by getting the last # subnode from the list /; if (cur == NULL || cur == ~_typ) cur = out.add_child(~_typ) ;; else out.add_child(~_typ) ;/ mod`.add_child(~out) return cur ;/ ;; else # Oh no! We hit a value! out.add_child(~_typ) return mod`.add_child(~out) ;/ out.add_child(~_typ) ;/ mod`.add_child(~out) # Properly parsed type list return mod ;/ /; _mhf_post (~utils.File fin, ~Node mod, ~Token first, bool lnok) [~Node] /; if (first`._type == TTYPE_KEYTP) Node id id.init(NTYPE_ID, first`.data) mod`.add_child(~id) first` = produce_next_token(fin, first`) /; if (id.eq("void\0") == true) _type_helper_func(fin, mod, first) ;; else if (first`.eq("`\0") == true) Node post post.init(NTYPE_POST_OP, first`.data) mod`.add_child(~post) first` = produce_next_token(fin, first`) ;/ /; if (first`._type == TTYPE_USRWD) return NULL ;/ return mod ;/ int ln = first`.line /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (first`._type == TTYPE_USRWD) Node id id.init(NTYPE_ID, first`.data) mod`.add_child(~id) first` = produce_next_token(fin, first`) ;; else return mod ;/ /; if (first`.line !== ln && lnok == false) return mod ;; else if (first`.eq(".\0") == true) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ln = first`.line ;; else if (first`.eq("(\0") == true || first`._type == TTYPE_USRWD) run = false ;; else return mod ;/ ;/ /; if (first`.eq("(\0") == true) ~Node weird = _mhf_post_list(fin, mod, first) # We get back right at the end paren of the list. # If the next token is a USRWD on the same line, # we want to return NULL, otherwise return the weird # pointer int ln = first`.line /; if (weird == mod && _advance_check(fin, first, ")\0") == true) /; if (first`._type == TTYPE_USRWD && (first`.line == ln || lnok == true)) return NULL ;/ ;/ return weird ;/ /; if (first`._type == TTYPE_USRWD) return NULL ;/ return mod ;/ # Transform type nodes into value nodes /; _mhf_transform (~Node _type, at) [~Node] Node out out.init(NTYPE_VALUE, utils.strcpy("\0")) ~Node sub, cur cur = ~out int idx = 0 /; loop (bool run = true; run == true && idx < _type`.sub.count) sub = _type`.sub.get(idx) /; if (sub`._type !== NTYPE_PRE_OP) run = false ;; else Node new new.init(NTYPE_PRE_OP, utils.strcpy(sub`.data)) cur = cur`.add_child(~new) idx++ ;/ ;/ /; loop (idx < _type`.sub.count && sub`._type == NTYPE_ID) /; if (idx < _type`.sub.count - 1) sub = _type`.sub.get(idx + 1) /; if (sub`._type == NTYPE_ID) sub = _type`.sub.get(idx) Node op, n op.init(NTYPE_BIN_OP, utils.strcpy(".\0")) n.init(NTYPE_ID, utils.strcpy(sub`.data)) /; if (cur`.sub.count == 0) op.add_child(~n) ;; else sub = cur`.sub.get(cur`.sub.count - 1) sub`.add_child(~n) op.add_child(sub) cur`.sub.pop() ;/ cur`.add_child(~op) ;; else sub = _type`.sub.get(idx) Node n n.init(NTYPE_ID, utils.strcpy(sub`.data)) /; if (cur`.sub.count !== 0) cur = cur`.sub.get(cur`.sub.count - 1) ;/ cur = cur`.add_child(~n) ;/ ;; else Node n n.init(NTYPE_ID, utils.strcpy(sub`.data)) /; if (cur`.sub.count !== 0) cur = cur`.sub.get(cur`.sub.count - 1) ;/ cur = cur`.add_child(~n) ;/ idx++ /; if (idx < _type`.sub.count) sub = _type`.sub.get(idx) ;/ ;/ ~int pt1 = at /; if (idx < _type`.sub.count && sub`._type == NTYPE_TLIST && sub`.eq("(\0") == true) Node lst lst.init(NTYPE_VLIST, utils.strcpy("(\0")) /; loop (int i = 0; i < sub`.sub.count) [i++] ~Node lsub = sub`.sub.get(i) at = _mhf_transform(lsub, at) ~int pt2 = lsub /; if (at == lsub) at = lst.add_child(lsub) ;; else lst.add_child(lsub) ;/ ;/ /; loop (sub`.sub.count > 0) sub`.sub.pop() ;/ ~int pt2 = sub /; if (pt1 == pt2) at = cur`.add_child(~lst) ;; else cur`.add_child(~lst) ;/ ;/ _type`.end() _type` = out return at ;/ /; _mhf_escape (~utils.File fin, ~Node mod, ~Token first, ~Node cur) int deep = 0 ~int p1 = cur ~int p2 = mod /; loop (bool run = true; run == true && p1 !== p2 && first`._type !== TTYPE_ERR) /; if (first`.eq(")\0") == true) /; if (deep > 0) deep = deep - 1 ;; else if (cur`.eq("(\0") == true) cur = cur`.parent p1 = cur ;; else /; loop (cur`.parent !== NULL && cur`.eq("(\0") == false) cur = cur`.parent ;/ /; if (cur`.parent == NULL) return ;/ cur = cur`.parent p1 = cur ;/ /; if (cur`.eq("(\0") == false) run = false; ;/ ;; else if (first`.eq("(\0") == true) deep = deep + 1 ;/ Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;/ /; _mhf_up_to_value (~Node cur) [~Node] ~int p1 = cur /; loop (p1 !== NULL) /; if (cur`._type == NTYPE_VALUE) return cur ;/ cur = cur`.parent p1 = cur ;/ return NULL ;/ /; _mhf_lower (~Node cur) [~Node] /; loop (bool run = true; run == true) /; if (cur`.sub.count > 0) cur = cur`.sub.get(cur`.sub.count - 1) ;; else return cur ;/ /; if (cur`.eq(".\0") || cur`._type == NTYPE_ID) return cur ;/ ;/ # should never happen return NULL ;/ /; _mhf_inner_value(~utils.File fin, ~Node cur, ~Token first) [~Node] cur = _mhf_lower(cur) /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (_advance_check(fin, first, ".\0") == true) /; if (first`._type == TTYPE_USRWD) Node op, id op.init(NTYPE_BIN_OP, utils.strcpy(".\0")) id.init(NTYPE_ID, first`.data) cur = cur`.parent ~Node sub = cur`.sub.get(cur`.sub.count - 1) op.add_child(sub) op.add_child(~id) cur`.sub.pop() cur = cur`.add_child(~op) first` = produce_next_token(fin, first`) ;; else _ast_print_err(fin, first, "Expected identifier after '.'\0") return NULL ;/ ;; else if (_op_postfix(first) == true) Node op op.init(NTYPE_POST_OP, first`.data) /; if (cur`.eq(".\0") == true) cur = cur`.sub.get(cur`.sub.count - 1) cur`.add_child(~op) cur = cur`.parent ;; else if (cur`._type == NTYPE_ID) cur`.add_child(~op) ;; else _ast_print_err(fin, first, "Unsure where we are at in the tree ('`'). [CMPERR]") op.end() return NULL ;/ first` = produce_next_token(fin, first`) ;; else if (first`.eq("(\0") == true) /; if (cur`.eq(".\0") == true) cur = cur`.sub.get(cur`.sub.count - 1) _ast_list_value(fin, first, cur) cur = cur`.parent ;; else if (cur`._type == NTYPE_ID) _ast_list_value(fin, first, cur) ;; else _ast_print_err(fin, first, "Unsure where we are at in the tree ('('). [CMPERR]") return NULL ;/ first` = produce_next_token(fin, first`) ;; else if (first`.eq("{\0") == true) Node ind ind.init(NTYPE_POST_OP, first`.data) first` = produce_next_token(fin, first`) /; if (_ast_value(fin, ~ind, first, true) == false) _ast_print_err(fin, first, "Expected value for index operation after '{'\0") ;/ /; if (cur`.eq(".\0") == true) cur = cur`.sub.get(cur`.sub.count - 1) cur`.add_child(~ind) cur = cur`.parent ;; else if (cur`._type == NTYPE_ID) cur`.add_child(~ind) ;; else _ast_print_err(fin, first, "Unsure where we are at in the tree ('{'). [CMPERR]") ind.end() return NULL ;/ /; if (_advance_check(fin, first, "}\0") == false) _ast_print_err(fin, first, "Expected '}' to show the end of an index operation after the value\0") return NULL ;/ ;; else run = false ;/ ;/ cur = _mhf_up_to_value(cur) /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (first`.eq(")\0") || first`.eq(",\0")) run = false ;; else if (first`.eq(".\0") == true) _ast_print_err(fin, first, "Unexpected token within function call. Expected binary operator then value, ',', or ')'.\0") return NULL ;; else if (first`._type == TTYPE_AUG && _op_bin(first) == true) Node bin bin.init(NTYPE_BIN_OP, first`.data) int i = _op_order(first`.data) bool gt = false /; if (cur`._type == NTYPE_BIN_OP) gt = _assoc(cur`.data, i) ;/ # Start from the top and work our way down /; loop (gt == true) cur = cur`.parent /; if (cur`._type == NTYPE_BIN_OP) gt = _assoc(cur`.data, i) ;; else gt = false ;/ ;/ ~Node lhs = cur`.sub.get(cur`.sub.count - 1) bin.add_child(lhs) cur`.sub.pop() cur = cur`.add_child(~bin) first` = produce_next_token(fin, first`) /; if (utils.strcmp(bin.data, "is\0")) _ast_type(fin, cur, first) ;; else run = _ast_value_bare(fin, cur, first, true) ;/ ;; else _ast_print_err(fin, first, "Unexpected token within function call. Expected binary operator then value, ',', or ')'.\0") return NULL ;/ ;/ cur = cur`.parent /; if (_advance_check(fin, first, ")\0")) /; if (cur`.eq("(\0") == true) cur = _mhf_up_to_value(cur) ;/ ;; else if (_advance_check(fin, first, ",\0") == false) _ast_print_err(fin, first, "Expected ')' or ',' to complete function call.\0") return NULL ;/ return cur ;/ /; _mhf_outer_list(~utils.File fin, ~Node cur, ~Token first) [~Node] /; loop (first`._type !== TTYPE_ERR && first`.eq(")\0") == false) _ast_value(fin, cur, first, true) /; if (_advance_check(fin, first, ",\0") == false && first`.eq(")\0") == false) _ast_print_err(fin, first, "Expected ',' to continue the value list or a closing delimiter\0") return NULL ;/ ;/ Token next = produce_next_token(fin, first`) first`.end() first` = next cur = _mhf_up_to_value(cur) return cur ;/ /; _mhf_finish_value (~utils.File fin, ~Node mod, ~Token first, ~Node cur, bool lnok) # First, if we are in a sub-list, we need to keep parsing as normal as if we were in _list_value ~int p1 = cur ~int p2 = mod int ln = first`.line bool firstRun = true # While we are in subtree /; loop (bool run = true; run == true && p1 !== p2 && first`._type !== TTYPE_ERR) # First loop for while we are in value /; if (cur`._type == NTYPE_VALUE) cur = _mhf_inner_value(fin, cur, first) ;/ # Second loop for while we are in val-list /; if (cur !== NULL && cur`._type == NTYPE_VLIST) cur = _mhf_outer_list(fin, cur, first) ;/ /; if (cur !== NULL && cur`._type !== NTYPE_VALUE && cur`._type !== NTYPE_VLIST) _ast_print_err(fin, first, "[CMPERR] Unsure where we are in the tree\n\0") print_ast(cur) return ;/ /; if (cur == NULL) # TODO: SOME ERR _ast_print_err(fin, first, "[CMPERR] Should escape but can't\n\0") # _mhf_escape(fin, mod, first, cur) return ;/ p1 = cur ;/ cur = _mhf_lower(cur) /; if (cur`.eq(".\0") == true) cur = cur`.sub.get(cur`.sub.count - 1) _astv_post_id(fin, cur, first, lnok) cur = cur`.parent ;; else if (cur`._type == NTYPE_ID) _astv_post_id(fin, cur, first, lnok) ;; else _ast_print_err(fin, first, "Unsure where we are at in the tree ('postid'). [CMPERR]") return ;/ cur = _mhf_up_to_value(cur) # After, we need to work similarly for the top value, however, # we need to keep track of line numbers so that we properly stop. /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (first`._type == TTYPE_SEP || _is_closing(first) == true) run = false ;; else if (first`.eq(".\0") == true) run = false ;; else if (first`._type == TTYPE_AUG && _op_bin(first) == true) Node bin bin.init(NTYPE_BIN_OP, first`.data) int i = _op_order(first`.data) bool gt = false /; if (cur`._type == NTYPE_BIN_OP) gt = _assoc(cur`.data, i) ;/ # Start from the top and work our way down /; loop (gt == true) cur = cur`.parent /; if (cur`._type == NTYPE_BIN_OP) gt = _assoc(cur`.data, i) ;; else gt = false ;/ ;/ ~Node lhs = cur`.sub.get(cur`.sub.count - 1) bin.add_child(lhs) cur`.sub.pop() cur = cur`.add_child(~bin) first` = produce_next_token(fin, first`) /; if (utils.strcmp(bin.data, "is\0")) _ast_type(fin, cur, first) ;; else run = _ast_value_bare(fin, cur, first, lnok) ;/ ;; else run = false ;/ ;/ ;/ /; _mhf_finish_decl (~utils.File fin, ~Node mod, ~Token first, bool lnok) Node out out.init(NTYPE_DECL, utils.strcpy("\0")) out.add_child(mod) /; loop (bool run = true; run == true) /; if (first`._type == TTYPE_USRWD) Node var var.init(NTYPE_ID, first`.data) int ln = first`.line first` = produce_next_token(fin, first`) /; if (first`.eq("=\0") && (first`.line == ln || lnok == true)) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp _ast_value(fin, ~var, first, false) ;; else if (first`.line !== ln && lnok == false) run = false ;/ out.add_child(~var) /; if (first`.eq(",\0") == false) run = false ;; else if (run == true) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;; else _ast_print_err(fin, first, "Expected variable name in declaration\0") run = false ;/ ;/ mod` = out ;/ /; _maybe_helper_fun (~utils.File fin, ~Node mod, ~Token first, bool lnok) # Try parsing as a type first, and if we encounter something weird we will transform # the output into a value before proceeding Node out out.init(NTYPE_TYPE, utils.strcpy("\0")) _type_helper_pre(fin, ~out, first) /; if (first`.eq("(\0")) _mhf_transform(~out) _mhf_finish_value(fin, ~out, first, ~out, lnok) ;; else if (first`._type !== TTYPE_USRWD && first`._type !== TTYPE_KEYTP) _ast_print_err(fin, first, "Unexpected token. Expected the completion of a declaration or value (identifier or '(')\0") ;; else # Post is a bit of a weird function. It returns a pointer the node where # _mhf_finish_value should begin merging in values, or zero in the case # that this looks like a proper declaration ~Node cur = _mhf_post(fin, ~out, first, lnok) /; if (cur == NULL) _mhf_finish_decl(fin, ~out, first, lnok) ;; else cur = _mhf_transform(~out, cur) _mhf_finish_value(fin, ~out, first, cur, lnok) ;/ ;/ mod`.add_child(~out) ;/ /; _ast_function (~utils.File fin, ~Node mod, ~Token first) /; if (first`._type !== TTYPE_USRWD) _ast_print_err(fin, first, "[FATAL] [CMPERR] Expected function name\0") return ;/ Node fn fn.init(NTYPE_FUNCTION, first`.data) first` = produce_next_token(fin, first`) /; if (first`.eq("(\0") == true) _ast_list_decl(fin, ~fn, first) ;/ /; if (first`.eq("[\0") == true) _ast_list_type(fin, ~fn, first) ;/ /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (_advance_check(fin, first, "asm\0") == true) _ast_asm(fin, ~fn, first) ;; else if (first`.eq("/;\0") == true) _ast_fun_block(fin, ~fn, first) ;; else if (first`._type == TTYPE_KEYTP || first`.eq("{\0") == true) _ast_decl(fin, ~fn, first) ;; else if (first`._type == TTYPE_USRWD || first`.eq("~\0") == true) _maybe_helper_fun(fin, ~fn, first, false) ;; else if (first`._type == TTYPE_LITRL || _op_prefix(first)) _ast_value(fin, ~fn, first, false) ;; else if (first`._type == TTYPE_KEYWD) _ast_keyword_expr(fin, ~fn, first) ;; else if (first`._type == TTYPE_DELIM && first`.data` == ';') run = false ;; else _ast_print_err(fin, first, "Expected definition, expression, or sub block in function\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;/ mod`.add_child(~fn) ;/ # Top level directives /; _ast_import (~utils.File fin, ~Node mod, ~Token first) /; if (first`._type !== TTYPE_LITRL || first`.data` !== '"') _ast_print_err(fin, first, "Expected string or import literal after 'import'\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp return ;/ ~uint8 rel = utils.unquote_str(first`.data) utils.File imp = fin`.relative(rel) _delete(rel) rel = imp.path.to_cstr('/') _printf("Importing \0") _printf(rel) _printf("\n\0") _delete(rel) _ast_file(~imp, mod) imp.end() Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ /; _ast_asm (~utils.File fin, ~Node mod, ~Token first) /; if (first`._type !== TTYPE_LITRL || first`.data` !== '"') _ast_print_err(fin, first, "Expected string literal after 'ast'\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp return ;/ Node an an.init(NTYPE_ASM, utils.unquote_str(first`.data)) mod`.add_child(~an) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ /; _ast_struct (~utils.File fin, ~Node mod, ~Token first) # Identifier check /; if (first`._type !== TTYPE_USRWD) _ast_print_err(fin, first, "Expected new identifier for typedef after 'struct'\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp return ;/ # Root struct node Node sct sct.init(NTYPE_STRUCT, first`.data) first` = produce_next_token(fin, first`) # Check for def list /; if (first`._type !== TTYPE_DELIM || first`.data` !== '{') _ast_print_err(fin, first, "Expected new identifier for typedef after 'struct'\0") mod`.add_child(~sct) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp return ;/ # Parse deflist and push root node into module _ast_list_decl(fin, ~sct, first) mod`.add_child(~sct) ;/ /; _ast_enum (~utils.File fin, ~Node mod, ~Token first) # Identifier check /; if (first`._type !== TTYPE_USRWD) _ast_print_err(fin, first, "Expected new identifier for def after 'enum'\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp return ;/ # Root struct node Node sct sct.init(NTYPE_ENUM, first`.data) first` = produce_next_token(fin, first`) # Check for enum type /; if (first`.data` == '[') _ast_list_type(fin, ~sct, first) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ # Check for def list /; if (first`._type !== TTYPE_DELIM || first`.data` !== '{') _ast_print_err(fin, first, "Expected new identifier for typedef after 'struct'\0") mod`.add_child(~sct) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp return ;/ # Parse deflist and push root node into module _ast_list_enum(fin, ~sct, first) mod`.add_child(~sct) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ /; _ast_decl (~utils.File fin, ~Node mod, ~Token first) Node decl decl.init(NTYPE_DECL, utils.strcpy("\0")) _ast_type(fin, ~decl, first) /; loop (bool run = true; run == true) /; if (first`._type == TTYPE_USRWD) Node var var.init(NTYPE_ID, first`.data) first` = produce_next_token(fin, first`) /; if (first`.eq("=\0")) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp _ast_value(fin, ~var, first, false) ;/ decl.add_child(~var) /; if (first`.eq(",\0") == false) run = false ;; else Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;; else _ast_print_err(fin, first, "Expected variable name in declaration\0") run = false ;/ ;/ mod`.add_child(~decl) ;/ /; _ast_top_block(~utils.File fin, ~Node mod, ~Token first) Token blf = first` first` = produce_next_token(fin, first`) /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (first`.eq("module\0") == true || first`.eq("export\0") == true) _ast_module(fin, mod, first) ;; else if (_advance_check(fin, first, "method\0") == true) _ast_method(fin, mod, first) ;; else if (first`._type == TTYPE_USRWD) _ast_function(fin, mod, first) ;; else _ast_print_err(fin, first, "Expected module, method, or function for top level block\0") ;/ run = _advance_check(fin, first, ";;\0") /; if (run == false && first`.eq(";/\0") == false && first`.eq(";;\0") == false) _ast_print_err(fin, first, "Block being skipped. Parsing will pick up after the end\0") ;/ ;/ _ast_block_pass(fin, first) /; if (first`.eq(";/\0") == false && first`.eq(";;\0") == false) _ast_print_err(fin, ~blf, "Could not find closing ;/ for top block\0") ;; else Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ blf.end() ;/ /; _ast_module(~utils.File fin, ~Node mod, ~Token first) uint16 nt = NTYPE_MODULE /; if (_advance_check(fin, first, "export\0") == true) /; if (_advance_check(fin, first, "module\0") == false) _ast_print_err(fin, first, "Expected 'module' keyword after 'export'\0") return ;/ nt = NTYPE_EXPORT ;; else if (_advance_check(fin, first, "module\0") == false) _printf("[FATAL] The following issue is with the compiler, not your program.\n\0") _printf("[FATAL] Please report the following issue to tnslc upstream.\n\0") _ast_print_err(fin, first, "[FATAL] [CMPERR] Should only call _ast_module when 'module' or 'export' are seen\0") ;/ /; if (first`._type !== TTYPE_USRWD) _ast_print_err(fin, first, "Expected module name (identifier) after 'module'\0") ;/ Node nmod nmod.init(nt, first`.data) first` = produce_next_token(fin, first`) /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (_advance_check(fin, first, "import\0") == true) _ast_import(fin, ~nmod, first) ;; else if (_advance_check(fin, first, "struct\0") == true) _ast_struct(fin, ~nmod, first) ;; else if (_advance_check(fin, first, "enum\0") == true) _ast_enum(fin, ~nmod, first) ;; else if (_advance_check(fin, first, "asm\0") == true) _ast_asm(fin, ~nmod, first) ;; else if (first`.eq("/;\0") == true) _ast_top_block(fin, ~nmod, first) ;; else if (first`._type == TTYPE_KEYTP || first`._type == TTYPE_USRWD || first`.eq("~\0") == true || first`.eq("{\0") == true) _ast_decl(fin, ~nmod, first) ;; else if (first`._type == TTYPE_DELIM && first`.data` == ';') run = false ;; else _ast_print_err(fin, first, "Expected 'import', 'struct', 'asm', block, or declaration in top level\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;/ mod`.add_child(~nmod) ;/ /; _ast_file (~utils.File fin, ~Node mod) fin`.open() Token first = produce_first_token(fin) /; loop (first._type !== TTYPE_ERR) /; if (_advance_check(fin, ~first, "import\0") == true) _ast_import(fin, mod, ~first) ;; else if (_advance_check(fin, ~first, "struct\0") == true) _ast_struct(fin, mod, ~first) ;; else if (_advance_check(fin, ~first, "enum\0") == true) _ast_enum(fin, mod, ~first) ;; else if (_advance_check(fin, ~first, "asm\0") == true) _ast_asm(fin, mod, ~first) ;; else if (first.eq("/;\0") == true) _ast_top_block(fin, mod, ~first) ;; else if (first._type == TTYPE_KEYTP || first._type == TTYPE_USRWD || first.eq("~\0") == true || first.eq("{\0") == true) _ast_decl(fin, mod, ~first) ;; else _ast_print_err(fin, ~first, "Expected 'import', 'struct', 'asm', block, or declaration in top level\0") Token tmp = produce_next_token(fin, first) first.end() first = tmp ;/ ;/ first.end() 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("MODULE\0") ;; else if (n`._type == NTYPE_EXPORT) _printf("EXPORT\0") ;; else if (n`._type == NTYPE_STRUCT) _printf("STRUCT\0") ;; else if (n`._type == NTYPE_TYPE) _printf("TYPE\0") ;; else if (n`._type == NTYPE_ID) _printf("ID\0") ;; else if (n`._type == NTYPE_BIN_OP) _printf("BIN_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_TLIST) _printf("TLIST\0") ;; else if (n`._type == NTYPE_DLIST) _printf("DLIST\0") ;; else if (n`._type == NTYPE_ELIST) _printf("ELIST\0") ;; else if (n`._type == NTYPE_SLIST) _printf("SLIST\0") ;; else if (n`._type == NTYPE_LITERAL) _printf("LITERAL\0") # ;; else if (n`._type == NTYPE_KEY_TYPE) # _printf("KEY_TYPE\0") ;; else if (n`._type == NTYPE_ENUM) _printf("ENUM\0") ;; else if (n`._type == NTYPE_DECL) _printf("DECL\0") ;; else if (n`._type == NTYPE_VLIST) _printf("VLIST\0") ;; else if (n`._type == NTYPE_VALUE) _printf("VALUE\0") ;; else if (n`._type == NTYPE_CAST) _printf("CAST\0") ;; else if (n`._type == NTYPE_FLOW_CONTROL) _printf("FLOW_CONTROL\0") ;; else if (n`._type == NTYPE_IF_BLOCK) _printf("IF_BLOCK\0") ;; else if (n`._type == NTYPE_ELIF_BLOCK) _printf("ELIF_BLOCK\0") ;; else if (n`._type == NTYPE_ELSE_BLOCK) _printf("ELSE_BLOCK\0") ;; else if (n`._type == NTYPE_LOOP_BLOCK) _printf("LOOP_BLOCK\0") ;; else if (n`._type == NTYPE_ASM) _printf("ASM\0") ;; else if (n`._type == NTYPE_EMPTY) _printf("EMPTY\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) /; if (verify_ast_integrity(n) == false) _printf("Integrity test failed\n\0") ;; else _printf("Integrity test passed\n\0") ;/ ;/ /; verify_ast_integrity (~Node n) [bool] /; loop (int i = 0; i < n`.sub.count) [i++] ~Node s = n`.sub.get(i) /; if (s`.parent !== n) _printf("Test failed at: \n\0") print_node_head(s) _printf("}\n\0") _printf("Parent: \n\0") print_node_head(n) _printf("}\n\0") ~int p = n int ptr = p _print_num("Expected: %p\n\0", ptr) ~int p = s`.parent ptr = p _print_num("Got: %p\n\0", ptr) return false ;/ /; if (verify_ast_integrity(s) == false) return false ;/ ;/ return true ;/