From 5fe1a219788d51097ef08ca7bf656be35aa8377a Mon Sep 17 00:00:00 2001 From: Max Wash Date: Fri, 13 Dec 2024 12:26:01 +0000 Subject: [PATCH] asm: implement an asm parser and emitter --- asm/assembler/assembler.c | 22 ++- asm/assembler/assembler.h | 2 + asm/assembler/class.c | 2 +- asm/assembler/constpool.c | 184 ++++++++++++++++++++++++ asm/include/ivy/asm/bin.h | 25 ++-- asm/include/ivy/asm/lex.h | 17 ++- asm/include/ivy/asm/parse.h | 19 +++ asm/lex.c | 44 +++--- asm/lex.h | 2 +- asm/parse/atom.c | 66 +++++++++ asm/{parse.c => parse/block.c} | 0 asm/parse/class.c | 0 asm/parse/constpool.c | 247 +++++++++++++++++++++++++++++++++ asm/parse/ident.c | 86 ++++++++++++ asm/parse/import.c | 0 asm/parse/parse.c | 172 +++++++++++++++++++++++ asm/parse/parse.h | 68 +++++++++ asm/parse/selector.c | 157 +++++++++++++++++++++ asm/parse/unit.c | 42 ++++++ 19 files changed, 1106 insertions(+), 49 deletions(-) create mode 100644 asm/parse/atom.c rename asm/{parse.c => parse/block.c} (100%) create mode 100644 asm/parse/class.c create mode 100644 asm/parse/constpool.c create mode 100644 asm/parse/ident.c create mode 100644 asm/parse/import.c create mode 100644 asm/parse/parse.c create mode 100644 asm/parse/parse.h create mode 100644 asm/parse/selector.c create mode 100644 asm/parse/unit.c diff --git a/asm/assembler/assembler.c b/asm/assembler/assembler.c index 6e5525c..05c537c 100644 --- a/asm/assembler/assembler.c +++ b/asm/assembler/assembler.c @@ -8,9 +8,11 @@ #include "assembler.h" extern struct assembler_scope_type class_scope_type; +extern struct assembler_scope_type constpool_scope_type; static const struct assembler_scope_type *scope_types[] = { [IVY_ASM_SCOPE_CLASS] = &class_scope_type, + [IVY_ASM_SCOPE_CONSTPOOL] = &constpool_scope_type, }; static const size_t nr_scope_types = sizeof scope_types / sizeof scope_types[0]; @@ -44,9 +46,14 @@ enum ivy_status ivy_assembler_create(FILE *fp, struct ivy_assembler **as) out->as_xdat = tmpfile(); struct ivy_bin_header header = {0}; + header.h_magic = b_i32_htob(0xAABBCCDD); fseek(fp, 0, SEEK_SET); fwrite(&header, sizeof header, 1, fp); + out->as_data_offset = sizeof header; + + char blank[16] = {0}; + assembler_write_extended_data(out, blank, sizeof blank); *as = out; return IVY_OK; @@ -66,7 +73,7 @@ enum ivy_status ivy_assembler_finish(struct ivy_assembler *as) size_t xdat_len = as->as_next_xdata_key; fseek(as->as_xdat, 0, SEEK_SET); - char *buf = malloc(buf_len); + unsigned char *buf = malloc(buf_len); if (!buf) { return IVY_ERR_NO_MEMORY; @@ -81,7 +88,7 @@ enum ivy_status ivy_assembler_finish(struct ivy_assembler *as) while (1) { size_t r = fread(buf, 1, buf_len, as->as_xdat); - fwrite(buf, 1, r, as->as_xdat); + fwrite(buf, 1, r, as->as_data); as->as_data_offset += r; if (r == buf_len) { @@ -98,7 +105,7 @@ enum ivy_status ivy_assembler_finish(struct ivy_assembler *as) free(buf); - unsigned int nr_table_entries = 0; + unsigned short nr_table_entries = 0; struct ivy_bin_header header = {0}; header.h_table_offset = b_i64_htob(as->as_data_offset); @@ -122,7 +129,7 @@ enum ivy_status ivy_assembler_finish(struct ivy_assembler *as) fwrite(&xdat, 1, sizeof xdat, as->as_data); nr_table_entries++; - header.h_table_len = b_i16_htob(nr_table_entries * sizeof(struct ivy_bin_table_entry)); + header.h_table_len = b_i16_htob(nr_table_entries); fseek(as->as_data, 0, SEEK_SET); fwrite(&header, 1, sizeof header, as->as_data); @@ -153,6 +160,11 @@ extended_data_key assembler_write_extended_data(struct ivy_assembler *as, const return key; } +struct assembler_scope *assembler_get_scope(struct ivy_assembler *as) +{ + return as->as_scope; +} + enum ivy_status ivy_assembler_begin_scope( struct ivy_assembler *as, enum ivy_assembler_scope_type type, ivy_assembler_attrib_table attrib) @@ -175,6 +187,8 @@ enum ivy_status ivy_assembler_begin_scope( return IVY_ERR_NO_MEMORY; } + memset(scope, 0x0, type_info->s_scope_size); + while ((as->as_data_offset % 16) != 0) { fputc(0, as->as_data); as->as_data_offset++; diff --git a/asm/assembler/assembler.h b/asm/assembler/assembler.h index a852db0..55f7ad4 100644 --- a/asm/assembler/assembler.h +++ b/asm/assembler/assembler.h @@ -48,4 +48,6 @@ struct assembler_scope_type { extern size_t assembler_write_data(struct ivy_assembler *as, const void *p, size_t len); extern extended_data_key assembler_write_extended_data(struct ivy_assembler *as, const void *p, size_t len); +extern struct assembler_scope *assembler_get_scope(struct ivy_assembler *as); + #endif \ No newline at end of file diff --git a/asm/assembler/class.c b/asm/assembler/class.c index dd54a8c..1dae63d 100644 --- a/asm/assembler/class.c +++ b/asm/assembler/class.c @@ -17,7 +17,7 @@ static enum ivy_status put_xval( struct ivy_assembler *as, struct assembler_scope *scope, enum ivy_assembler_xval_type type, - ivy_assembler_attrib_table attrib) + const ivy_assembler_attrib_table attrib) { struct ivy_bin_class_table_entry entry = {0}; switch (type) { diff --git a/asm/assembler/constpool.c b/asm/assembler/constpool.c index e69de29..86d84f9 100644 --- a/asm/assembler/constpool.c +++ b/asm/assembler/constpool.c @@ -0,0 +1,184 @@ +#include "assembler.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct constpool_assembler_scope { + struct assembler_scope s_base; + b_dict *s_strings; +}; + +static enum ivy_status init_scope( + struct ivy_assembler *as, struct assembler_scope *scope, + const ivy_assembler_attrib_table attrib) +{ + struct ivy_bin_constpool header = {0}; + + assembler_write_data(as, &header, sizeof header); + + struct constpool_assembler_scope *c = (struct constpool_assembler_scope *)scope; + c->s_strings = b_dict_create(); + + return IVY_OK; +} + +static ivy_bin_data_handle get_cached_string(struct constpool_assembler_scope *scope, const char *s) +{ + b_number *key = b_dict_at(scope->s_strings, s); + if (!key) { + return IVY_BIN_NULL_HANDLE; + } + + return (ivy_bin_data_handle)b_number_get_int32(key); +} + +static void put_cached_string(struct constpool_assembler_scope *scope, const char *s, ivy_bin_data_handle key) +{ + b_dict_put(scope->s_strings, s, B_RV_INT32(key)); +} + +static ivy_bin_data_handle write_string(struct ivy_assembler *as, const char *s) +{ + struct constpool_assembler_scope *scope = (struct constpool_assembler_scope *)assembler_get_scope(as); + + ivy_bin_data_handle key = get_cached_string(scope, s); + if (key != IVY_BIN_NULL_HANDLE) { + return key; + } + + size_t len = strlen(s); + + struct ivy_bin_string str = { 0 }; + str.s_hash = b_i32_htob(b_hash_string(s)); + str.s_len = b_i32_htob(len); + + key = assembler_write_extended_data(as, &str, sizeof str); + + /* include the trailing null terminator. */ + assembler_write_extended_data(as, s, len + 1); + + put_cached_string(scope, s, key); + + return key; +} + +static ivy_bin_data_handle write_selector(struct ivy_assembler *as, const struct ivy_selector *sel) +{ + struct ivy_bin_selector dat = {0}; + switch (sel->sel_recipient) { + case IVY_SEL_CLASS: + dat.sel_flags = IVY_BIN_SELECTOR_CLASS; + break; + case IVY_SEL_OBJECT: + dat.sel_flags = IVY_BIN_SELECTOR_OBJECT; + break; + default: + return IVY_BIN_NULL_HANDLE; + } + + if (sel->sel_name) { + dat.sel_name = b_i32_htob(write_string(as, sel->sel_name)); + } + + unsigned int i = 0; + unsigned int nr_args = b_queue_length(&sel->sel_args); + /* TODO hash. */ + + ivy_bin_data_handle *arg_handles = calloc(nr_args, sizeof(ivy_bin_data_handle)); + + b_queue_iterator it = {0}; + b_queue_foreach (&it, &sel->sel_args) { + struct ivy_selector_arg *arg = b_unbox(struct ivy_selector_arg, it.entry, arg_entry); + arg_handles[i++] = write_string(as, arg->arg_label); + } + + ivy_bin_data_handle selector_handle = assembler_write_extended_data(as, &dat, sizeof dat); + for (i = 0; i < nr_args; i++) { + b_i32 arg_handle = b_i32_htob(arg_handles[i]); + assembler_write_extended_data(as, &arg_handle, sizeof arg_handle); + } + + free(arg_handles); + return selector_handle; +} + +static ivy_bin_data_handle write_ident(struct ivy_assembler *as, const struct ivy_ident *id) +{ + struct ivy_bin_ident dat = {0}; + /* TODO hash. */ + + unsigned int nr_parts = b_queue_length(&id->id_parts); + unsigned int i = 0; + + ivy_bin_data_handle *part_handles = calloc(nr_parts, sizeof(ivy_bin_data_handle)); + b_queue_iterator it = {0}; + b_queue_foreach (&it, &id->id_parts) { + struct ivy_ident_part *arg = b_unbox(struct ivy_ident_part, it.entry, p_entry); + part_handles[i++] = write_string(as, arg->p_str); + } + + dat.id_nr_parts = (uint8_t)nr_parts; + + ivy_bin_data_handle ident_handle = assembler_write_extended_data(as, &dat, sizeof dat); + + for (i = 0; i < nr_parts; i++) { + b_i32 part_handle = b_i32_htob(part_handles[i]); + assembler_write_extended_data(as, &part_handle, sizeof part_handle); + } + + free(part_handles); + return ident_handle; +} + +static enum ivy_status put_pval( + struct ivy_assembler *as, struct assembler_scope *scope, + enum ivy_assembler_pval_type type, unsigned long index, const void *val) +{ + struct ivy_bin_constpool_table_entry entry = {0}; + uintptr_t i = *(uintptr_t *)val; + + switch (type) { + case IVY_ASM_PVAL_STRING: + entry.e_type = b_i32_htob(IVY_CONSTPOOL_TABLE_STRING); + entry.e_ex_handle = b_i32_htob(write_string(as, val)); + break; + case IVY_ASM_PVAL_IDENT: + entry.e_type = b_i32_htob(IVY_CONSTPOOL_TABLE_IDENT); + entry.e_ex_handle = b_i32_htob(write_ident(as, val)); + break; + case IVY_ASM_PVAL_ATOM: + entry.e_type = b_i32_htob(IVY_CONSTPOOL_TABLE_ATOM); + entry.e_ex_handle = b_i32_htob(write_string(as, val)); + break; + case IVY_ASM_PVAL_SINT: + entry.e_type = b_i32_htob(IVY_CONSTPOOL_TABLE_INT); + entry.e_int = b_i32_htob((uint32_t)i); + break; + case IVY_ASM_PVAL_UINT: + entry.e_type = b_i32_htob(IVY_CONSTPOOL_TABLE_UINT); + entry.e_int = b_i32_htob((uint32_t)i); + break; + case IVY_ASM_PVAL_SELECTOR: + entry.e_type = b_i32_htob(IVY_CONSTPOOL_TABLE_SELECTOR); + entry.e_ex_handle = b_i32_htob(write_selector(as, val)); + break; + default: + return IVY_ERR_NOT_SUPPORTED; + } + + assembler_write_data(as, &entry, sizeof entry); + return IVY_OK; +} + +const struct assembler_scope_type constpool_scope_type = { + .s_scope_size = sizeof(struct constpool_assembler_scope), + .s_init_scope = init_scope, + .s_put_pval = put_pval, +}; \ No newline at end of file diff --git a/asm/include/ivy/asm/bin.h b/asm/include/ivy/asm/bin.h index d09d66d..0daa644 100644 --- a/asm/include/ivy/asm/bin.h +++ b/asm/include/ivy/asm/bin.h @@ -68,7 +68,7 @@ struct ivy_bin_class { }; struct ivy_bin_lambda { - ivy_bin_data_handle l_ident; + b_i32 l_ident; b_i32 l_instr[]; }; @@ -78,12 +78,6 @@ struct ivy_bin_msgh { b_i32 msg_instr[]; }; -struct ivy_bin_constpool_header { - b_i32 c_nr_table_entries; - uint8_t c_reserved[4]; - b_i64 c_table_offset; -}; - struct ivy_bin_string { b_i32 s_hash; b_i32 s_len; @@ -95,25 +89,30 @@ struct ivy_bin_selector { uint8_t sel_nr_args; uint8_t sel_reserved[2]; b_i32 sel_hash; - ivy_bin_data_handle sel_name; - ivy_bin_data_handle sel_args[]; + b_i32 sel_name; + b_i32 sel_args[]; }; struct ivy_bin_ident { b_i32 id_hash; uint8_t id_nr_parts; uint8_t id_reserved[3]; - ivy_bin_data_handle id_parts[]; + b_i32 id_parts[]; }; struct ivy_bin_constpool_table_entry { b_i32 e_type; - b_i32 e_reserved; union { - b_i32 e_handle; - b_i64 e_int; + b_i32 e_ex_handle; + b_i32 e_int; }; }; +struct ivy_bin_constpool { + uint8_t c_reserved[16]; + struct ivy_bin_constpool_table_entry c_table[]; +}; + + #endif diff --git a/asm/include/ivy/asm/lex.h b/asm/include/ivy/asm/lex.h index de4fb41..94f83fb 100644 --- a/asm/include/ivy/asm/lex.h +++ b/asm/include/ivy/asm/lex.h @@ -1,6 +1,7 @@ #ifndef IVY_ASM_LEX_H_ #define IVY_ASM_LEX_H_ +#include #include #include #include @@ -8,6 +9,7 @@ enum ivy_asm_token_type { IVY_ASM_TOK_NONE = 0, + __IVY_ASM_TOK_INDEX_BASE = 100, IVY_ASM_TOK_KEYWORD, IVY_ASM_TOK_SYMBOL, IVY_ASM_TOK_INT, @@ -16,23 +18,26 @@ enum ivy_asm_token_type { IVY_ASM_TOK_IDENT, IVY_ASM_TOK_STRING, IVY_ASM_TOK_LINEFEED, + __IVY_ASM_TOK_INDEX_LIMIT, }; enum ivy_asm_keyword { IVY_ASM_KW_NONE = 0, - IVY_ASM_KW_USE, + __IVY_ASM_KW_INDEX_BASE = 200, IVY_ASM_KW_IDENT, - IVY_ASM_KW_SELECTOR, IVY_ASM_KW_ATOM, - IVY_ASM_KW_LAMBDA, + IVY_ASM_KW_SELECTOR, + IVY_ASM_KW_IMPORT, + IVY_ASM_KW_BLOCK, IVY_ASM_KW_CONSTPOOL, IVY_ASM_KW_CLASS, - IVY_ASM_KW_MSGH, IVY_ASM_KW_END, + __IVY_ASM_KW_INDEX_LIMIT, }; enum ivy_asm_symbol { IVY_ASM_SYM_NONE = 0, + __IVY_ASM_SYM_INDEX_BASE = 300, IVY_ASM_SYM_DOT, IVY_ASM_SYM_COMMA, IVY_ASM_SYM_LEFT_PAREN, @@ -45,15 +50,17 @@ enum ivy_asm_symbol { IVY_ASM_SYM_SEMICOLON, IVY_ASM_SYM_DOLLAR, IVY_ASM_SYM_HYPHEN, + IVY_ASM_SYM_PLUS, IVY_ASM_SYM_SQUOTE, IVY_ASM_SYM_DQUOTE, IVY_ASM_SYM_FORWARD_SLASH_ASTERISK, IVY_ASM_SYM_ASTERISK_FORWARD_SLASH, + __IVY_ASM_SYM_INDEX_LIMIT, }; struct ivy_asm_token { enum ivy_asm_token_type t_type; - struct ivy_asm_token *t_next; + b_queue_entry t_entry; union { enum ivy_asm_keyword t_keyword; diff --git a/asm/include/ivy/asm/parse.h b/asm/include/ivy/asm/parse.h index e69de29..9540db3 100644 --- a/asm/include/ivy/asm/parse.h +++ b/asm/include/ivy/asm/parse.h @@ -0,0 +1,19 @@ +#ifndef IVY_ASM_PARSE_H_ +#define IVY_ASM_PARSE_H_ + +#include + +struct ivy_asm_parser; +struct ivy_asm_token; +struct ivy_assembler; + +IVY_API enum ivy_status ivy_asm_parser_create(struct ivy_asm_parser **out); +IVY_API void ivy_asm_parser_destroy(struct ivy_asm_parser *p); + +IVY_API void ivy_asm_parser_set_assembler( + struct ivy_asm_parser *p, struct ivy_assembler *as); + +IVY_API enum ivy_status ivy_asm_parser_push_token( + struct ivy_asm_parser *p, struct ivy_asm_token *tok); + +#endif diff --git a/asm/lex.c b/asm/lex.c index 47f63a1..41ac251 100644 --- a/asm/lex.c +++ b/asm/lex.c @@ -21,14 +21,13 @@ } static struct lex_token_def keywords[] = { - LEX_TOKEN_DEF(IVY_ASM_KW_USE, "@use"), + LEX_TOKEN_DEF(IVY_ASM_KW_IMPORT, "@import"), LEX_TOKEN_DEF(IVY_ASM_KW_IDENT, "@ident"), LEX_TOKEN_DEF(IVY_ASM_KW_SELECTOR, "@selector"), LEX_TOKEN_DEF(IVY_ASM_KW_ATOM, "@atom"), - LEX_TOKEN_DEF(IVY_ASM_KW_LAMBDA, "@lambda"), LEX_TOKEN_DEF(IVY_ASM_KW_CONSTPOOL, "@constpool"), LEX_TOKEN_DEF(IVY_ASM_KW_CLASS, "@class"), - LEX_TOKEN_DEF(IVY_ASM_KW_MSGH, "@msgh"), + LEX_TOKEN_DEF(IVY_ASM_KW_BLOCK, "@block"), LEX_TOKEN_DEF(IVY_ASM_KW_END, "@end"), }; static const size_t nr_keywords = sizeof keywords / sizeof keywords[0]; @@ -249,10 +248,14 @@ enum ivy_status ivy_asm_lexer_create(struct ivy_asm_lexer **lexp) void ivy_asm_lexer_destroy(struct ivy_asm_lexer *lex) { - while (lex->lex_queue) { - struct ivy_asm_token *next = lex->lex_queue->t_next; - ivy_asm_token_destroy(lex->lex_queue); - lex->lex_queue = next; + b_queue_iterator it = {0}; + b_queue_iterator_begin(&lex->lex_queue, &it); + + while (b_queue_iterator_is_valid(&it)) { + struct ivy_asm_token *tok + = b_unbox(struct ivy_asm_token, it.entry, t_entry); + b_queue_iterator_erase(&it); + ivy_asm_token_destroy(tok); } if (lex->lex_linebuf) { @@ -399,13 +402,7 @@ static struct ivy_asm_token *create_token(enum ivy_asm_token_type type) static enum ivy_status push_token( struct ivy_asm_lexer *lex, struct ivy_asm_token *tok) { - struct ivy_asm_token **slot = &lex->lex_queue; - - while (*slot) { - slot = &(*slot)->t_next; - } - - *slot = tok; + b_queue_push_back(&lex->lex_queue, &tok->t_entry); lex->lex_prev_token = tok->t_type; return IVY_OK; } @@ -953,7 +950,7 @@ struct ivy_asm_token *ivy_asm_lexer_peek(struct ivy_asm_lexer *lex) { enum ivy_status status = IVY_OK; - while (!lex->lex_queue) { + while (b_queue_empty(&lex->lex_queue)) { status = pump_tokens(lex); if (status != IVY_OK) { @@ -963,7 +960,8 @@ struct ivy_asm_token *ivy_asm_lexer_peek(struct ivy_asm_lexer *lex) } lex->lex_status = status; - struct ivy_asm_token *tok = lex->lex_queue; + b_queue_entry *entry = b_queue_first(&lex->lex_queue); + struct ivy_asm_token *tok = b_unbox(struct ivy_asm_token, entry, t_entry); return tok; } @@ -971,7 +969,7 @@ struct ivy_asm_token *ivy_asm_lexer_read(struct ivy_asm_lexer *lex) { enum ivy_status status = IVY_OK; - while (!lex->lex_queue) { + while (b_queue_empty(&lex->lex_queue)) { status = pump_tokens(lex); if (status != IVY_OK) { @@ -980,11 +978,8 @@ struct ivy_asm_token *ivy_asm_lexer_read(struct ivy_asm_lexer *lex) } } - struct ivy_asm_token *tok = lex->lex_queue; - - if (tok) { - lex->lex_queue = tok->t_next; - } + b_queue_entry *entry = b_queue_pop_front(&lex->lex_queue); + struct ivy_asm_token *tok = b_unbox(struct ivy_asm_token, entry, t_entry); return tok; } @@ -1028,14 +1023,13 @@ const char *ivy_asm_keyword_to_string(enum ivy_asm_keyword keyword) { switch (keyword) { ENUM_STR(IVY_ASM_KW_NONE); - ENUM_STR(IVY_ASM_KW_USE); ENUM_STR(IVY_ASM_KW_IDENT); ENUM_STR(IVY_ASM_KW_SELECTOR); ENUM_STR(IVY_ASM_KW_ATOM); - ENUM_STR(IVY_ASM_KW_LAMBDA); ENUM_STR(IVY_ASM_KW_CONSTPOOL); ENUM_STR(IVY_ASM_KW_CLASS); - ENUM_STR(IVY_ASM_KW_MSGH); + ENUM_STR(IVY_ASM_KW_BLOCK); + ENUM_STR(IVY_ASM_KW_IMPORT); ENUM_STR(IVY_ASM_KW_END); default: return ""; diff --git a/asm/lex.h b/asm/lex.h index 198dad1..47a2b04 100644 --- a/asm/lex.h +++ b/asm/lex.h @@ -38,7 +38,7 @@ struct ivy_asm_lexer { b_dict *lex_keywords; enum ivy_status lex_status; - struct ivy_asm_token *lex_queue; + b_queue lex_queue; enum ivy_asm_token_type lex_prev_token; b_string *lex_temp; diff --git a/asm/parse/atom.c b/asm/parse/atom.c new file mode 100644 index 0000000..1ad76c2 --- /dev/null +++ b/asm/parse/atom.c @@ -0,0 +1,66 @@ +#include "parse.h" +#include +#include +#include +#include + +struct atom_parser_state { + struct parser_state s_base; + unsigned int s_prev_token; + + struct ivy_asm_token *s_name; +}; + +static enum ivy_status init_state( + struct ivy_asm_parser *ctx, struct parser_state *s) +{ + struct atom_parser_state *state = (struct atom_parser_state *)s; + state->s_prev_token = IVY_ASM_SYM_LEFT_PAREN; + return IVY_OK; +} + +static enum ivy_status parse_ident( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct atom_parser_state *state = (struct atom_parser_state *)asm_parser_get_state(ctx); + if (state->s_prev_token != IVY_ASM_SYM_LEFT_PAREN) { + return IVY_ERR_BAD_SYNTAX; + } + + if (state->s_name) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_name = tok; + state->s_prev_token = IVY_ASM_TOK_IDENT; + + return IVY_OK; +} + +static enum ivy_status parse_right_paren( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct atom_parser_state *state = (struct atom_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_TOK_IDENT) { + return IVY_ERR_BAD_SYNTAX; + } + + if (!state->s_name) { + return IVY_ERR_BAD_SYNTAX; + } + + asm_parser_pop_state(ctx, state->s_name); + return IVY_OK; +} + +struct parser_state_type atom_parser_state_type = { + .n_init_state = init_state, + .n_state_size = sizeof(struct atom_parser_state), + .n_token_parsers = { + TOK_PARSER(IDENT, parse_ident), + }, + .n_symbol_parsers = { + SYM_PARSER(RIGHT_PAREN, parse_right_paren), + }, +}; \ No newline at end of file diff --git a/asm/parse.c b/asm/parse/block.c similarity index 100% rename from asm/parse.c rename to asm/parse/block.c diff --git a/asm/parse/class.c b/asm/parse/class.c new file mode 100644 index 0000000..e69de29 diff --git a/asm/parse/constpool.c b/asm/parse/constpool.c new file mode 100644 index 0000000..edcfcfa --- /dev/null +++ b/asm/parse/constpool.c @@ -0,0 +1,247 @@ +#include "parse.h" +#include +#include +#include +#include + +struct constpool_parser_state { + struct parser_state s_base; + unsigned int s_prev_token; + + enum ivy_assembler_pval_type s_current_pval_type; + + union { + struct ivy_selector *sel; + struct ivy_ident *ident; + struct ivy_asm_token *tok; + } s_current_pval_val; + + bool s_current_index_set; + unsigned int s_current_index; +}; + +static enum ivy_status parse_linefeed(struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct constpool_parser_state *state = (struct constpool_parser_state *)asm_parser_get_state(ctx); + struct ivy_bin_constpool_table_entry entry = {0}; + + state->s_prev_token = IVY_ASM_TOK_LINEFEED; + + if (!state->s_current_index_set) { + /* no index set */ + return IVY_OK; + } + + struct ivy_asm_token *tmp = NULL; + + switch (state->s_current_pval_type) { + case IVY_ASM_PVAL_IDENT: + entry.e_type = b_i32_htob(IVY_CONSTPOOL_TABLE_IDENT); + entry.e_ex_handle = b_i32_htob(ivy_assembler_put_pval(ctx->p_assembler, IVY_ASM_PVAL_IDENT, state->s_current_index, state->s_base.s_previous_value)); + ivy_ident_destroy(state->s_base.s_previous_value); + break; + case IVY_ASM_PVAL_ATOM: + tmp = state->s_base.s_previous_value; + entry.e_type = b_i32_htob(IVY_CONSTPOOL_TABLE_ATOM); + entry.e_ex_handle = b_i32_htob(ivy_assembler_put_pval(ctx->p_assembler, IVY_ASM_PVAL_ATOM, state->s_current_index, tmp->t_str)); + ivy_asm_token_destroy(tmp); + break; + case IVY_ASM_PVAL_SINT: + entry.e_type = b_i32_htob(IVY_CONSTPOOL_TABLE_INT); + entry.e_int = b_i32_htob(state->s_current_pval_val.tok->t_int.v); + break; + case IVY_ASM_PVAL_UINT: + entry.e_type = b_i32_htob(IVY_CONSTPOOL_TABLE_UINT); + entry.e_int = b_i32_htob(state->s_current_pval_val.tok->t_int.uv); + break; + case IVY_ASM_PVAL_SELECTOR: + entry.e_type = b_i32_htob(IVY_CONSTPOOL_TABLE_SELECTOR); + entry.e_ex_handle = b_i32_htob(ivy_assembler_put_pval(ctx->p_assembler, IVY_ASM_PVAL_SELECTOR, state->s_current_index, state->s_base.s_previous_value)); + ivy_selector_destroy(state->s_base.s_previous_value); + break; + case IVY_ASM_PVAL_STRING: + tmp = state->s_current_pval_val.tok; + entry.e_type = b_i32_htob(IVY_CONSTPOOL_TABLE_STRING); + entry.e_ex_handle = b_i32_htob(ivy_assembler_put_pval(ctx->p_assembler, IVY_ASM_PVAL_STRING, state->s_current_index, tmp->t_str)); + ivy_asm_token_destroy(tmp); + break; + default: + return IVY_ERR_BAD_SYNTAX; + } + + state->s_current_index = 0; + state->s_current_index_set = false; + state->s_current_pval_type = IVY_ASM_PVAL_NONE; + state->s_base.s_previous_value = NULL; + + return IVY_OK; +} + +static enum ivy_status parse_int( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct constpool_parser_state *state = (struct constpool_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token == IVY_ASM_SYM_COLON) { + /* this is a const value. */ + state->s_current_pval_type = IVY_ASM_PVAL_UINT; + state->s_current_pval_val.tok = tok; + state->s_prev_token = IVY_ASM_TOK_INT; + return IVY_OK; + } + + if (!state->s_current_index_set) { + state->s_current_index = tok->t_int.uv; + state->s_current_index_set = true; + state->s_prev_token = IVY_ASM_TOK_INT; + return IVY_OK; + } + + /* not sure what this is but we aren't expecting it. */ + return IVY_ERR_BAD_SYNTAX; +} + +static enum ivy_status parse_colon( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct constpool_parser_state *state = (struct constpool_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_TOK_INT) { + /* not expected at this time */ + return IVY_ERR_BAD_SYNTAX; + } + + state->s_prev_token = IVY_ASM_SYM_COLON; + + return IVY_OK; +} + +static enum ivy_status parse_string( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct constpool_parser_state *state = (struct constpool_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_SYM_COLON) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_current_pval_type = IVY_ASM_PVAL_STRING; + state->s_current_pval_val.tok = tok; + state->s_prev_token = IVY_ASM_TOK_STRING; + + return IVY_OK; +} + +static enum ivy_status parse_atom( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct constpool_parser_state *state = (struct constpool_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_SYM_COLON) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_current_pval_type = IVY_ASM_PVAL_ATOM; + state->s_current_pval_val.tok = tok; + state->s_prev_token = IVY_ASM_KW_ATOM; + + return IVY_OK; +} + +static enum ivy_status parse_kw_ident( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct constpool_parser_state *state = (struct constpool_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_SYM_COLON) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_current_pval_type = IVY_ASM_PVAL_IDENT; + state->s_current_pval_val.tok = tok; + state->s_prev_token = IVY_ASM_KW_IDENT; + + return IVY_OK; +} + +static enum ivy_status parse_selector( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct constpool_parser_state *state = (struct constpool_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_SYM_COLON) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_current_pval_type = IVY_ASM_PVAL_SELECTOR; + state->s_prev_token = IVY_ASM_KW_SELECTOR; + + return IVY_OK; +} + +static enum ivy_status parse_end( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct constpool_parser_state *state = (struct constpool_parser_state *)asm_parser_get_state(ctx); + + if (state->s_current_index_set) { + return IVY_ERR_BAD_SYNTAX; + } + + asm_parser_pop_state(ctx, NULL); + + return IVY_OK; +} + +static enum ivy_status parse_left_paren( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct constpool_parser_state *state = (struct constpool_parser_state *)asm_parser_get_state(ctx); + + switch (state->s_prev_token) { + case IVY_ASM_KW_SELECTOR: + asm_parser_push_state(ctx, ASM_PARSER_SELECTOR); + break; + case IVY_ASM_KW_IDENT: + asm_parser_push_state(ctx, ASM_PARSER_IDENT); + break; + case IVY_ASM_KW_ATOM: + asm_parser_push_state(ctx, ASM_PARSER_ATOM); + break; + default: + return IVY_ERR_BAD_SYNTAX; + } + + return IVY_OK; +} + +static void init_state(struct ivy_asm_parser *ctx, struct parser_state *state) +{ + ivy_assembler_begin_scope(ctx->p_assembler, IVY_ASM_SCOPE_CONSTPOOL, NULL); +} + +static void finish_state(struct ivy_asm_parser *ctx, struct parser_state *state) +{ + ivy_assembler_end_scope(ctx->p_assembler); +} + +struct parser_state_type constpool_parser_state_type = { + .n_init_state = init_state, + .n_finish_state = finish_state, + .n_state_size = sizeof(struct constpool_parser_state), + .n_token_parsers = { + TOK_PARSER(INT, parse_int), + TOK_PARSER(STRING, parse_string), + TOK_PARSER(LINEFEED, parse_linefeed), + }, + .n_symbol_parsers = { + SYM_PARSER(COLON, parse_colon), + SYM_PARSER(LEFT_PAREN, parse_left_paren), + }, + .n_keyword_parsers = { + KW_PARSER(IDENT, parse_kw_ident), + KW_PARSER(SELECTOR, parse_selector), + KW_PARSER(ATOM, parse_atom), + KW_PARSER(END, parse_end), + } +}; \ No newline at end of file diff --git a/asm/parse/ident.c b/asm/parse/ident.c new file mode 100644 index 0000000..73c926a --- /dev/null +++ b/asm/parse/ident.c @@ -0,0 +1,86 @@ +#include "parse.h" +#include +#include +#include +#include + +struct ident_parser_state { + struct parser_state s_base; + unsigned int s_prev_token; + + b_queue s_parts; +}; + +static enum ivy_status init_state( + struct ivy_asm_parser *ctx, struct parser_state *s) +{ + struct ident_parser_state *state = (struct ident_parser_state *)s; + state->s_prev_token = IVY_ASM_SYM_LEFT_PAREN; + return IVY_OK; +} + +static enum ivy_status parse_ident( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct ident_parser_state *state = (struct ident_parser_state *)asm_parser_get_state(ctx); + if (state->s_prev_token != IVY_ASM_SYM_LEFT_PAREN && state->s_prev_token != IVY_ASM_SYM_DOT) { + return IVY_ERR_BAD_SYNTAX; + } + + b_queue_push_back(&state->s_parts, &tok->t_entry); + state->s_prev_token = IVY_ASM_TOK_IDENT; + + return IVY_OK; +} + +static enum ivy_status parse_dot( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct ident_parser_state *state = (struct ident_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_TOK_IDENT) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_prev_token = IVY_ASM_SYM_DOT; + + return IVY_OK; +} + +static enum ivy_status parse_right_paren( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct ident_parser_state *state = (struct ident_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_TOK_IDENT) { + return IVY_ERR_BAD_SYNTAX; + } + + struct ivy_ident *ident = ivy_ident_create(); + + b_queue_iterator it = {0}; + b_queue_iterator_begin(&state->s_parts, &it); + while (b_queue_iterator_is_valid(&it)) { + struct ivy_asm_token *tok = b_unbox(struct ivy_asm_token, it.entry, t_entry); + b_queue_iterator_erase(&it); + + ivy_ident_add_part(ident, tok->t_str); + ivy_asm_token_destroy(tok); + } + + asm_parser_pop_state(ctx, ident); + + return IVY_OK; +} + +struct parser_state_type ident_parser_state_type = { + .n_init_state = init_state, + .n_state_size = sizeof(struct ident_parser_state), + .n_token_parsers = { + TOK_PARSER(IDENT, parse_ident), + }, + .n_symbol_parsers = { + SYM_PARSER(DOT, parse_dot), + SYM_PARSER(RIGHT_PAREN, parse_right_paren), + }, +}; \ No newline at end of file diff --git a/asm/parse/import.c b/asm/parse/import.c new file mode 100644 index 0000000..e69de29 diff --git a/asm/parse/parse.c b/asm/parse/parse.c new file mode 100644 index 0000000..4ee7519 --- /dev/null +++ b/asm/parse/parse.c @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include "parse.h" + +extern struct parser_state_type unit_parser_state_type; +extern struct parser_state_type constpool_parser_state_type; +extern struct parser_state_type ident_parser_state_type; +extern struct parser_state_type selector_parser_state_type; +extern struct parser_state_type atom_parser_state_type; + +static const struct parser_state_type *parser_state_types[] = { + [ASM_PARSER_UNIT] = &unit_parser_state_type, + [ASM_PARSER_CONSTPOOL] = &constpool_parser_state_type, + [ASM_PARSER_IDENT] = &ident_parser_state_type, + [ASM_PARSER_SELECTOR] = &selector_parser_state_type, + [ASM_PARSER_ATOM] = &atom_parser_state_type, +}; +static const size_t nr_parser_state_types = sizeof parser_state_types / sizeof parser_state_types[0]; + +enum ivy_status ivy_asm_parser_create(struct ivy_asm_parser **out) +{ + struct ivy_asm_parser *parser = malloc(sizeof *parser); + + if (!parser) { + return IVY_ERR_NO_MEMORY; + } + + memset(parser, 0x0, sizeof *parser); + + asm_parser_push_state(parser, ASM_PARSER_UNIT); + + *out = parser; + return IVY_OK; +} + +void ivy_asm_parser_destroy(struct ivy_asm_parser *p) +{ + free(p); +} + +void ivy_asm_parser_set_assembler( + struct ivy_asm_parser *p, struct ivy_assembler *as) +{ + p->p_assembler = as; +} + +static token_parse_function get_token_parser(struct parser_state *state, struct ivy_asm_token *tok) +{ + struct parser_state_type *type = state->s_type; + if (!type) { + return NULL; + } + + token_parse_function specific_parser = NULL; + token_parse_function specific_fallback_parser = NULL; + token_parse_function token_parser = type->n_token_parsers[__TOK_PARSER_INDEX(tok->t_type)]; + token_parse_function token_fallback_parser = type->n_token_parsers[__TOK_PARSER_FALLBACK_INDEX]; + + switch (tok->t_type) { + case IVY_ASM_TOK_SYMBOL: + specific_parser = type->n_symbol_parsers[__SYM_PARSER_INDEX(tok->t_symbol)]; + specific_fallback_parser = type->n_symbol_parsers[__SYM_PARSER_FALLBACK_INDEX]; + break; + case IVY_ASM_TOK_KEYWORD: + specific_parser = type->n_keyword_parsers[__KW_PARSER_INDEX(tok->t_keyword)]; + specific_fallback_parser = type->n_keyword_parsers[__KW_PARSER_FALLBACK_INDEX]; + break; + default: + break; + } + + if (specific_parser) + return specific_parser; + if (specific_fallback_parser) + return specific_fallback_parser; + if (token_parser) + return token_parser; + if (token_fallback_parser) + return token_fallback_parser; + return NULL; +} + +enum ivy_status ivy_asm_parser_push_token( + struct ivy_asm_parser *p, struct ivy_asm_token *tok) +{ + struct parser_state *state = asm_parser_get_state(p); + if (!state) { + return IVY_ERR_NOT_SUPPORTED; + } + + token_parse_function f = get_token_parser(state, tok); + if (!f) { + if (tok->t_type == IVY_ASM_TOK_LINEFEED) { + ivy_asm_token_destroy(tok); + return IVY_OK; + } + + return IVY_ERR_BAD_SYNTAX; + } + + return f(p, tok); +} + +static struct parser_state_type *get_parser_state_type(enum parser_state_type_id type) +{ + if (type < 0 || type >= nr_parser_state_types) { + return NULL; + } + + return parser_state_types[type]; +} + +struct parser_state *asm_parser_push_state(struct ivy_asm_parser *parser, enum parser_state_type_id type) +{ + struct parser_state_type *type_info = get_parser_state_type(type); + + if (!type_info) { + return NULL; + } + + struct parser_state *state = malloc(type_info->n_state_size); + + if (!state) { + return NULL; + } + + memset(state, 0x0, type_info->n_state_size); + + state->s_type = type_info; + + if (type_info->n_init_state) { + type_info->n_init_state(parser, state); + } + + b_queue_push_back(&parser->p_state, &state->s_entry); + + return state; +} + +void asm_parser_pop_state(struct ivy_asm_parser *parser, void *ret) +{ + b_queue_entry *last = b_queue_pop_back(&parser->p_state); + if (!last) { + return; + } + + struct parser_state *state = b_unbox(struct parser_state, last, s_entry); + + if (state->s_type->n_finish_state) { + state->s_type->n_finish_state(parser, state); + } + + free(state); + + state = asm_parser_get_state(parser); + if (state) { + state->s_previous_value = ret; + } +} + +struct parser_state *asm_parser_get_state(struct ivy_asm_parser *parser) +{ + b_queue_entry *last = b_queue_last(&parser->p_state); + + if (!last) { + return NULL; + } + + return b_unbox(struct parser_state, last, s_entry); +} diff --git a/asm/parse/parse.h b/asm/parse/parse.h new file mode 100644 index 0000000..7ae7cc0 --- /dev/null +++ b/asm/parse/parse.h @@ -0,0 +1,68 @@ +#ifndef _PARSE_PARSE_H_ +#define _PARSE_PARSE_H_ + +#include +#include + +#define __TOK_PARSER_INDEX(x) ((x)-__IVY_ASM_TOK_INDEX_BASE) +#define __SYM_PARSER_INDEX(x) ((x)-__IVY_ASM_SYM_INDEX_BASE) +#define __KW_PARSER_INDEX(x) ((x)-__IVY_ASM_KW_INDEX_BASE) + +#define __TOK_PARSER_FALLBACK_INDEX IVY_ASM_TOK_NONE +#define __SYM_PARSER_FALLBACK_INDEX IVY_ASM_SYM_NONE +#define __KW_PARSER_FALLBACK_INDEX IVY_ASM_KW_NONE + +#define TOK_PARSER(id, func) [__TOK_PARSER_INDEX(IVY_ASM_TOK_##id)] = func +#define SYM_PARSER(id, func) [__SYM_PARSER_INDEX(IVY_ASM_SYM_##id)] = func +#define KW_PARSER(id, func) [__KW_PARSER_INDEX(IVY_ASM_KW_##id)] = func + +#define TOK_PARSER_FALLBACK(func) [__TOK_PARSER_FALLBACK_INDEX] = func +#define SYM_PARSER_FALLBACK(func) [__SYM_PARSER_FALLBACK_INDEX] = func +#define KW_PARSER_FALLBACK(func) [__KW_PARSER_FALLBACK_INDEX] = func + +struct ivy_asm_parser; + +enum parser_state_type_id { + ASM_PARSER_NONE = 0, + ASM_PARSER_UNIT, + ASM_PARSER_CLASS, + ASM_PARSER_CONSTPOOL, + ASM_PARSER_IMPORT, + ASM_PARSER_BLOCK, + ASM_PARSER_SELECTOR, + ASM_PARSER_IDENT, + ASM_PARSER_ATOM, +}; + +typedef enum ivy_status (*token_parse_function)( + struct ivy_asm_parser *, struct ivy_asm_token *); + +struct parser_state_type { + size_t n_state_size; + + void (*n_init_state)(struct ivy_asm_parser *, struct parser_state *); + void (*n_finish_state)(struct ivy_asm_parser *, struct parser_state *); + enum ivy_status (*n_add_child)( + struct parser_state *, struct ivy_ast_node *); + + token_parse_function n_token_parsers[__TOK_PARSER_INDEX(__IVY_ASM_TOK_INDEX_LIMIT)]; + token_parse_function n_keyword_parsers[__KW_PARSER_INDEX(__IVY_ASM_KW_INDEX_LIMIT)]; + token_parse_function n_symbol_parsers[__SYM_PARSER_INDEX(__IVY_ASM_SYM_INDEX_LIMIT)]; +}; + +struct parser_state { + b_queue_entry s_entry; + const struct parser_state_type *s_type; + void *s_previous_value; +}; + +struct ivy_asm_parser { + struct ivy_assembler *p_assembler; + b_queue p_state; +}; + +extern struct parser_state *asm_parser_push_state(struct ivy_asm_parser *parser, enum parser_state_type_id type); +extern void asm_parser_pop_state(struct ivy_asm_parser *parser, void *ret); +extern struct parser_state *asm_parser_get_state(struct ivy_asm_parser *parser); + +#endif diff --git a/asm/parse/selector.c b/asm/parse/selector.c new file mode 100644 index 0000000..437a4e9 --- /dev/null +++ b/asm/parse/selector.c @@ -0,0 +1,157 @@ +#include "parse.h" +#include +#include +#include +#include + +struct selector_parser_state { + struct parser_state s_base; + unsigned int s_prev_token; + + unsigned int s_paren_depth; + struct ivy_asm_token *s_prev_label; + struct ivy_selector *s_sel; +}; + +static enum ivy_status init_state( + struct ivy_asm_parser *ctx, struct parser_state *s) +{ + struct selector_parser_state *state = (struct selector_parser_state *)s; + state->s_prev_token = IVY_ASM_SYM_LEFT_PAREN; + return ivy_selector_create(&state->s_sel); +} + +static enum ivy_status parse_ident( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct selector_parser_state *state = (struct selector_parser_state *)asm_parser_get_state(ctx); + if (state->s_prev_token == IVY_ASM_TOK_LABEL && state->s_prev_label) { + ivy_selector_add_arg(state->s_sel, state->s_prev_label->t_str, tok->t_str); + ivy_asm_token_destroy(tok); + ivy_asm_token_destroy(state->s_prev_label); + state->s_prev_label = tok; + state->s_prev_token = IVY_ASM_TOK_LABEL; + return IVY_OK; + } + + if (state->s_prev_token != IVY_ASM_SYM_LEFT_PAREN && state->s_prev_token != IVY_ASM_SYM_HYPHEN && state->s_prev_token != IVY_ASM_SYM_PLUS) { + return IVY_ERR_BAD_SYNTAX; + } + + ivy_selector_set_name(state->s_sel, tok->t_str); + ivy_asm_token_destroy(tok); + state->s_prev_token = IVY_ASM_TOK_IDENT; + + return IVY_OK; +} + +static enum ivy_status parse_label( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct selector_parser_state *state = (struct selector_parser_state *)asm_parser_get_state(ctx); + if (state->s_prev_token != IVY_ASM_SYM_LEFT_PAREN + && state->s_prev_token != IVY_ASM_TOK_LABEL + && state->s_prev_token != IVY_ASM_SYM_HYPHEN + && state->s_prev_token != IVY_ASM_SYM_PLUS) { + return IVY_ERR_BAD_SYNTAX; + } + + if (state->s_prev_label) { + ivy_selector_add_arg(state->s_sel, state->s_prev_label->t_str, NULL); + ivy_asm_token_destroy(state->s_prev_label); + state->s_prev_label = NULL; + } + + state->s_prev_label = tok; + state->s_prev_token = IVY_ASM_TOK_LABEL; + + return IVY_OK; +} + +static enum ivy_status parse_hyphen( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct selector_parser_state *state = (struct selector_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_SYM_LEFT_PAREN) { + return IVY_ERR_BAD_SYNTAX; + } + + ivy_selector_set_recipient(state->s_sel, IVY_SEL_OBJECT); + state->s_prev_token = IVY_ASM_SYM_HYPHEN; + + return IVY_OK; +} + +static enum ivy_status parse_plus( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct selector_parser_state *state = (struct selector_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_SYM_LEFT_PAREN) { + return IVY_ERR_BAD_SYNTAX; + } + + ivy_selector_set_recipient(state->s_sel, IVY_SEL_CLASS); + state->s_prev_token = IVY_ASM_SYM_PLUS; + + return IVY_OK; +} + +static enum ivy_status parse_left_paren( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct selector_parser_state *state = (struct selector_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_TOK_IDENT) { + return IVY_ERR_BAD_SYNTAX; + } + + if (state->s_paren_depth > 0) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_paren_depth++; + state->s_prev_token = IVY_ASM_SYM_LEFT_PAREN; + + return IVY_OK; +} + +static enum ivy_status parse_right_paren( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct selector_parser_state *state = (struct selector_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_TOK_IDENT && state->s_prev_token != IVY_ASM_TOK_LABEL && state->s_prev_token != IVY_ASM_SYM_RIGHT_PAREN) { + return IVY_ERR_BAD_SYNTAX; + } + + if (state->s_prev_label) { + ivy_selector_add_arg(state->s_sel, state->s_prev_label->t_str, NULL); + ivy_asm_token_destroy(state->s_prev_label); + state->s_prev_label = NULL; + } + + if (state->s_paren_depth > 0) { + state->s_paren_depth--; + return IVY_OK; + } + + asm_parser_pop_state(ctx, state->s_sel); + return IVY_OK; +} + +struct parser_state_type selector_parser_state_type = { + .n_init_state = init_state, + .n_state_size = sizeof(struct selector_parser_state), + .n_token_parsers = { + TOK_PARSER(IDENT, parse_ident), + TOK_PARSER(LABEL, parse_label), + }, + .n_symbol_parsers = { + SYM_PARSER(HYPHEN, parse_hyphen), + SYM_PARSER(PLUS, parse_plus), + SYM_PARSER(LEFT_PAREN, parse_left_paren), + SYM_PARSER(RIGHT_PAREN, parse_right_paren), + }, +}; \ No newline at end of file diff --git a/asm/parse/unit.c b/asm/parse/unit.c new file mode 100644 index 0000000..a6b9cb0 --- /dev/null +++ b/asm/parse/unit.c @@ -0,0 +1,42 @@ +#include "parse.h" + +struct unit_parser_state { + struct parser_state s_base; +}; + +static enum ivy_status parse_constpool(struct ivy_asm_parser* ctx, struct ivy_asm_token* tok) +{ + asm_parser_push_state(ctx, ASM_PARSER_CONSTPOOL); + return IVY_OK; +} + +static enum ivy_status parse_import( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + asm_parser_push_state(ctx, ASM_PARSER_IMPORT); + return IVY_OK; +} + +static enum ivy_status parse_block( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + asm_parser_push_state(ctx, ASM_PARSER_BLOCK); + return IVY_OK; +} + +static enum ivy_status parse_class( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + asm_parser_push_state(ctx, ASM_PARSER_CLASS); + return IVY_OK; +} + +struct parser_state_type unit_parser_state_type = { + .n_state_size = sizeof(struct unit_parser_state), + .n_keyword_parsers = { + KW_PARSER(CONSTPOOL, parse_constpool), + KW_PARSER(IMPORT, parse_import), + KW_PARSER(CLASS, parse_class), + KW_PARSER(BLOCK, parse_block), + }, +}; \ No newline at end of file