diff options
| -rw-r--r-- | examples/std.ek | 66 | ||||
| -rw-r--r-- | src/actualize.c | 2 | ||||
| -rw-r--r-- | src/parser.y | 96 |
3 files changed, 92 insertions, 72 deletions
diff --git a/examples/std.ek b/examples/std.ek index dbf3a8c..fda6d23 100644 --- a/examples/std.ek +++ b/examples/std.ek @@ -22,16 +22,21 @@ pub typedef i27 {} pub typedef i9 { fmt![]; fmt(*i9 i, string args => result![string]) { - return ok!("123".str()); + /* hmm, this static string would have to be deinitialized + * somewhere else with possibly bad results. Should free() or + * whatever I choose to use check if the pointer is in static + * memory or something? Or should it be the user's + * responsibility to ensure static strings are cloned? */ + return ok!(string!("123")); } cmp![]; eq(*i9 i, *i9 o => bool) { - return *i == *o; + return i* == o*; } cmp(*i9 i, *i9 o => bool) { - return *i - *o; + return i* - o*; } hash![]; @@ -50,7 +55,7 @@ pub typedef str { fmt(*i9 s, string args => result![string]) { /* here we should probably copy s in case it is statically * defined */ - return {.len = 2, .buf = "cp"} as string; + return ok!(string!("cp")); } cmp![]; @@ -93,7 +98,7 @@ pub typedef string { } pub define string(s) { - {.len = sizeof(s), .buf = s} as string; + string!{.len = sizeof(s), .buf = s} } /* result import */ @@ -102,16 +107,22 @@ pub typedef result[any T] { T val; err(*result r => bool) { - return r.err != null; + return r*.err != null; } } pub define ok(v) { - {.err = null, .val = v} as result; + result!{.err = null, .val = v}; } pub define err(e) { - {.err = e} as result; + /* for this to work properly, I'll probably need some pretty decent type + * decuction...*/ + result!{.err = e}; +} + +pub define errv(e, v) { + result!{.err = e, .val = v}; } /* fmt import */ @@ -119,13 +130,12 @@ pub define fmt[] { fmt(*fmt p, string args => result![string]); str(*fmt p => string) { /* is this a loop? allowed? */ - /* alternative would be {.len = 0, .buf = ""} as string I guess*/ - const r = p.fmt(string!("")); - if r.err() { + const r = p*.fmt(string!("")); + if r*.err() { abort("error converting to string"); } - return r.v; + return r*.v; } } @@ -135,7 +145,7 @@ pub typedef file { } /* here would be useful if macros could take type arguments as well, for example - * f must be a file and fmt must be a string, but I guess this is a quick I can + * f must be a file and fmt must be a string, but I guess this is a quirk I can * live with... */ pub define fprint(f, fmt, ...args) { /* possible name clash, hmmm */ @@ -186,7 +196,7 @@ pub typedef vec[any T] { // we want our vector to be formattable, used by print etc. fmt![]; fmt(*vec v, string args => result![string]) { - return ok!("test".str()); + return ok!(string!("test")); } usize len; @@ -194,47 +204,47 @@ pub typedef vec[any T] { ^(usize) alloc; init(*vec v, ^(usize) alloc) { - v.len = 0; - v.buf = null; - v.alloc = alloc; + v*.len = 0; + v*.buf = null; + v*.alloc = alloc; } init(*vec v) { - init(v, alloc); + v*.init(alloc); } length(*vec v => usize) { return v.len; } index(*vec v, usize i => T) { - assert(i < v.len, "index %zu out of bounds\n", i); - return &v.buf[i]; + assert(i < v*.len, "index %zu out of bounds\n", i); + return &v*.buf[i]; } index(*vec v, isize i => T) { if i < 0 { - assert(-i < v.len, "reverse index %zi out of bounds\n", i); - return &v.buf[v.len + i]; + assert(-i < v*.len, "reverse index %zi out of bounds\n", i); + return &v*.buf[v*.len + i]; } /* v.whatever() is effectively syntactic sugar for * whatever::typeof(v)(&v), but since I don't allow typeof() * it's built-in. */ - return v.index(i as usize); + return v*.index(i as usize); } - prepend(*vec v, T e) { v.insert(e, 0); } - append(*vec v, T e) { v.insert(e, v.len); } + prepend(*vec v, T e) { v*.insert(e, 0); } + append(*vec v, T e) { v*.insert(e, v*.len); } - preplace(*vec v, T e) { v.place(e, 0); } - applace(*vec v, T e) { v.place(e, v.len); } + preplace(*vec v, T e) { v*.place(e, 0); } + applace(*vec v, T e) { v*.place(e, v*.len); } place(*vec v, T e) {} insert(*vec v, T e) {} deinit(*vec v) { - for (usize i = 0); i < v.len; i += 1 { + for i27 i = 0; i < v.len; i += 1 { deinit(v[i]); v[i] = null; } diff --git a/src/actualize.c b/src/actualize.c index 60e5108..3460851 100644 --- a/src/actualize.c +++ b/src/actualize.c @@ -2041,8 +2041,6 @@ static int actualize_dot(struct act_state *state, struct ast_node *id = AST_DOT(node).id; struct ast_node *type = expr->type; - if (AST_TYPE(type).kind == AST_TYPE_POINTER) - type = AST_PTR_TYPE(type).base; struct ast_node *def = NULL; switch (AST_TYPE(type).kind) { diff --git a/src/parser.y b/src/parser.y index c92ecf1..14fbb50 100644 --- a/src/parser.y +++ b/src/parser.y @@ -122,7 +122,7 @@ %left "::" /* why doesn't bison allow <*> for %nterm? would be so much easier */ -%nterm <node> import binop unop arg args decls expr +%nterm <node> import binop unop decls expr %nterm <node> while do_while statement statements body references macro %nterm <node> exprs if for case cases switch const %nterm <node> func_sign type var_decl var @@ -133,20 +133,20 @@ %nterm <node> construct construct_args construct_arg %nterm <node> statelet apply types -%nterm <node> tagged_struct +%nterm <node> tagged_struct expr_if /* constant operations */ %nterm <node> const_expr const_unop const_binop %nterm <node> macro_expand type_expand -%nterm <node> type_params type_param +%nterm <node> type_params type_param opt_for_inits for_inits for_init /* array stuff */ %nterm <node> arr arr_inits arr_init /* optional stuff */ -%nterm <node> opt_args opt_exprs proc_decl member opt_members +%nterm <node> opt_exprs proc_decl member opt_members %nterm <node> opt_statements opt_types opt_type_params %{ @@ -276,35 +276,23 @@ unop : "-" expr { $$ = gen_unop(AST_NEG, $2, src_loc(@$)); } | "!" expr { $$ = gen_unop(AST_LNOT, $2, src_loc(@$)); } | "&" expr { $$ = gen_unop(AST_REF, $2, src_loc(@$)); } - | "*" expr { $$ = gen_unop(AST_DEREF, $2, src_loc(@$)); } + | expr "*" { $$ = gen_unop(AST_DEREF, $1, src_loc(@$)); } arr_init - : "=>" const_expr "..." const_expr "=" arg { + : "=>" const_expr "..." const_expr "=" expr { $$ = gen_var($2, $4, $6, src_loc(@$)); } - | "=>" const_expr "=" arg { + | "=>" const_expr "=" expr { $$ = gen_var($2, NULL, $4, src_loc(@$)); } - | arg + | expr arr_inits : arr_init "," arr_inits { $$ = $1; $1->next = $3; } | arr_init arr - : "[" arr_inits "]" { $$ = $2; } - -arg - : "&" var_decl { $$ = gen_unop(AST_REF, $2, src_loc(@$)); } - | expr - | switch - | if - | arr - | body - -args - : arg "," args { $$ = $1; $1->next = $3; } - | arg + : "!" "[" arr_inits "]" { $$ = $3; } param_decl : type { $$ = gen_var(NULL, $1, NULL, src_loc(@$)); } @@ -378,20 +366,32 @@ expr $$ = gen_string(clone_string($1), src_loc(@$)); } | "(" expr ")" { $$ = $2; } - | expr "(" args ")" { $$ = gen_call($1, $3, src_loc(@$)); } - | expr "(" ")" { $$ = gen_call($1, NULL, src_loc(@$)); } - | expr "[" expr "]" { $$ = gen_arr_access($1, $3, src_loc(@$)); /** @todo add arr access */} - | "(" var_init ")" { $$ = $2; } + /* special rule, user is allowed to define new variables in if + * statements etc but it should stand out, which is why we require + * parentheses. Also because otherwise the parser craps itself lol */ + | "(" var ")" { $$ = $2; } + /* by adding "do" some statement-like things become expressions. It was + * either this or adding parentheses around them, I personally think + * "do" looks a bit cleaner. There is the slight annoyance that a very + * long do {} ... might have a 'while'; at the end, not sure if do ... + * while should be removed from the language altogether or what */ + | "do" body { $$ = $2; } + | "do" expr_if { $$ = $2; } + | "do" "const" expr_if { $$ = $3; } + | "do" switch { $$ = $2; } + | "do" "const" switch { $$ = $3; } + | expr "(" opt_exprs ")" { $$ = gen_call($1, $3, src_loc(@$)); } + | expr "[" expr "]" { $$ = gen_arr_access($1, $3, src_loc(@$)); } | "sizeof" expr { $$ = gen_sizeof($2, src_loc(@$)); } | expr "as" type { $$ = gen_cast($1, $3, src_loc(@$)); } | id "::" type { $$ = gen_fetch($1, $3, src_loc(@$)); } - | "as" type { $$ = gen_as($2, src_loc(@$)); } /** @todo might be uneccessary? */ | macro_expand | construct | assign | embed | binop | unop + | arr | id while @@ -407,7 +407,7 @@ goto : "goto" id { $$ = gen_goto(gen_label($2, src_loc(@$)), src_loc(@$)); } statelet - : "return" args { $$ = gen_return($2, src_loc(@$)); } + : "return" exprs { $$ = gen_return($2, src_loc(@$)); } | "return" { $$ = gen_return(NULL, src_loc(@$)); } | "break" { $$ = gen_ctrl(AST_CTRL_BREAK, src_loc(@$)); } | "continue" { $$ = gen_ctrl(AST_CTRL_CONTINUE, src_loc(@$)); } @@ -470,7 +470,6 @@ macro ast_set_flags($6, AST_FLAG_UNHYGIENIC); } | "define" id "(" references "..." id ")" body { - /* TODO: the location data of the variadic ID is way off */ ast_append($4, $6); $$ = gen_macro_construct($2, $4, $8, src_loc(@$)); ast_set_flags($$, AST_FLAG_VARIADIC); @@ -496,8 +495,12 @@ construct_args | construct_arg construct - : "{" construct_args "}" { - $$ = gen_init($2, src_loc(@$)); + : apply "{" construct_args "}" { + /** @todo add type info? */ + $$ = gen_init($3, src_loc(@$)); + } + | apply "[" opt_types "]" "{" construct_args "}" { + $$ = gen_init($6, src_loc(@$)); } if @@ -505,21 +508,30 @@ if | "if" expr body "else" body { $$ = gen_if($2, $3, $5, src_loc(@$)); } | "if" expr body "else" if { $$ = gen_if($2, $3, $5, src_loc(@$)); } -opt_args - : args - | {$$ = NULL;} +expr_if + : "if" expr body "else" body { $$ = gen_if($2, $3, $5, src_loc(@$)); } + | "if" expr body "else" expr_if { $$ = gen_if($2, $3, $5, src_loc(@$)); } opt_exprs : exprs | {$$ = NULL;} +for_init + : expr + | var_init + +for_inits + : for_init "," for_inits { $$ = $1; $$->next = $3; } + | for_init + +opt_for_inits + : for_inits + | {$$ = NULL;} + for - : "for" opt_args ";" opt_exprs ";" exprs body { + : "for" opt_for_inits ";" opt_exprs ";" opt_exprs body { $$ = gen_for($2, $4, $6, $7, src_loc(@$)); } - | "for" opt_args ";" opt_exprs ";" body { - $$ = gen_for($2, $4, NULL, $6, src_loc(@$)); - } case : "case" const_expr ":" statements { @@ -539,7 +551,7 @@ switch /* could there be a use case for number based iteration? */ const_for - : "for" id ":" args body { + : "for" id ":" exprs body { /* TODO: should id be a separate rule? */ $$ = gen_for($2, NULL, $4, $5, src_loc(@$)); ast_set_flags($5, AST_FLAG_UNHYGIENIC); @@ -614,9 +626,9 @@ var_decl : type id { $$ = gen_var($2, $1, NULL, src_loc(@$)); } var_init - : var_decl "=" arg { $$ = $1; $$->_var.init = $3; } - | "const" id "=" arg { $$ = gen_var($2, NULL, $4, src_loc(@$)); } - | "mut" id "=" arg { + : var_decl "=" expr { $$ = $1; $$->_var.init = $3; } + | "const" id "=" expr { $$ = gen_var($2, NULL, $4, src_loc(@$)); } + | "mut" id "=" expr { $$ = gen_var($2, NULL, $4, src_loc(@$)); ast_set_flags($$, AST_FLAG_MUTABLE); } @@ -653,7 +665,7 @@ opt_members | {$$ = NULL;} macro_expand - : apply "(" opt_args ")" { + : apply "(" opt_exprs ")" { $$ = gen_macro_expand($1, $3, src_loc(@$)); } |
