aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-02-26 03:12:24 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2024-02-26 03:12:24 +0200
commit2bdf1f8b1856bca8091d66a7a447e6c90993c297 (patch)
tree2b1bceb8beac7435907a30ca45c2cdab09e0df6b
parent89a907ddd0b7f6b888c61d54e3e41a8cee00b971 (diff)
downloadek-2bdf1f8b1856bca8091d66a7a447e6c90993c297.tar.gz
ek-2bdf1f8b1856bca8091d66a7a447e6c90993c297.zip
remove args from grammar
+ Expressions are slightly more powerful as a result and the parser is a bit simpler
-rw-r--r--examples/std.ek66
-rw-r--r--src/actualize.c2
-rw-r--r--src/parser.y96
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(@$));
}