X-Git-Url: https://ocean-lang.org/code/?p=ocean;a=blobdiff_plain;f=csrc%2Foceani.mdc;h=f2cc254612da9316433537ee9e4dba91f128deb4;hp=e7976cf086ef03b338527549a4d3d069af7afd45;hb=f34d3718d70bd38d10eeeb1bb42d0f3e2e6c978b;hpb=ef3bbba20f9e426125498f78fe3b1f4ea75de68a diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index e7976cf..f2cc254 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -804,6 +804,7 @@ which might be reported in error messages. int (*cmp_eq)(struct type *t1, struct type *t2, struct value *v1, struct value *v2); void (*dup)(struct type *type, struct value *vold, struct value *vnew); + int (*test)(struct type *type, struct value *val); void (*free)(struct type *type, struct value *val); void (*free_type)(struct type *t); long long (*to_int)(struct value *v); @@ -1168,6 +1169,11 @@ A separate function encoding these cases will simplify some code later. static void _free_value(struct type *type, struct value *v); + static int bool_test(struct type *type, struct value *v) + { + return v->bool; + } + static struct type base_prototype = { .init = _val_init, .print = _print_value, @@ -1198,6 +1204,7 @@ A separate function encoding these cases will simplify some code later. ###### context initialization Tbool = add_base_type(&context, "Boolean", Vbool, sizeof(char)); + Tbool->test = bool_test; Tstr = add_base_type(&context, "string", Vstr, sizeof(struct text)); Tnum = add_base_type(&context, "number", Vnum, sizeof(mpq_t)); Tnone = add_base_type(&context, "none", Vnone, 0); @@ -2305,7 +2312,7 @@ with a const size by whether they are prepared at parse time or not. if (!parse_time) return 1; if (type->array.member->size <= 0) - return 0; + return 0; // UNTESTED type->array.static_size = 1; type->size = type->array.size * type->array.member->size; @@ -3650,10 +3657,17 @@ expression operator, and the `CMPop` non-terminal will match one of them. ### Expressions: Arithmetic etc. The remaining expressions with the highest precedence are arithmetic, -string concatenation, and string conversion. String concatenation +string concatenation, string conversion, and testing. String concatenation (`++`) has the same precedence as multiplication and division, but lower than the uniary. +Testing comes in two forms. A single question mark (`?`) is a uniary +operator which converts come types into Boolean. The general meaning is +"is this a value value" and there will be more uses as the language +develops. A double questionmark (`??`) is a binary operator (Choose), +with same precedence as multiplication, which returns the LHS if it +tests successfully, else returns the RHS. + String conversion is a temporary feature until I get a better type system. `$` is a prefix operator which expects a string and returns a number. @@ -3669,15 +3683,15 @@ parentheses around an expression converts it into a Term, ###### Binode types Plus, Minus, Times, Divide, Rem, - Concat, - Absolute, Negate, + Concat, Choose, + Absolute, Negate, Test, StringConv, Bracket, ###### declare terminals $LEFT + - Eop - $LEFT * / % ++ Top - $LEFT Uop $ + $LEFT * / % ++ ?? Top + $LEFT Uop $ ? $TERM ( ) ###### expression grammar @@ -3722,11 +3736,13 @@ parentheses around an expression converts it into a Term, Uop -> + ${ $0.op = Absolute; }$ | - ${ $0.op = Negate; }$ | $ ${ $0.op = StringConv; }$ + | ? ${ $0.op = Test; }$ Top -> * ${ $0.op = Times; }$ | / ${ $0.op = Divide; }$ | % ${ $0.op = Rem; }$ | ++ ${ $0.op = Concat; }$ + | ?? ${ $0.op = Choose; }$ ###### print binode cases case Plus: @@ -3735,6 +3751,7 @@ parentheses around an expression converts it into a Term, case Divide: case Concat: case Rem: + case Choose: if (bracket) printf("("); print_exec(b->left, indent, bracket); switch(b->op) { @@ -3744,6 +3761,7 @@ parentheses around an expression converts it into a Term, case Divide: fputs(" / ", stdout); break; case Rem: fputs(" % ", stdout); break; case Concat: fputs(" ++ ", stdout); break; + case Choose: fputs(" ?? ", stdout); break; default: abort(); // NOTEST } // NOTEST print_exec(b->right, indent, bracket); @@ -3752,11 +3770,13 @@ parentheses around an expression converts it into a Term, case Absolute: case Negate: case StringConv: + case Test: if (bracket) printf("("); switch (b->op) { case Absolute: fputs("+", stdout); break; case Negate: fputs("-", stdout); break; case StringConv: fputs("$", stdout); break; + case Test: fputs("?", stdout); break; default: abort(); // NOTEST } // NOTEST print_exec(b->right, indent, bracket); @@ -3804,6 +3824,25 @@ parentheses around an expression converts it into a Term, prog, type, 0, NULL); return Tnum; + case Test: + /* LHS must support ->test, result is Tbool */ + t = propagate_types(b->right, c, perr, NULL, 0); + if (!t || !t->test) + type_err(c, "error: '?' requires a testable value, not %1", + prog, t, 0, NULL); + return Tbool; + + case Choose: + /* LHS and RHS must match and are returned. Must support + * ->test + */ + t = propagate_types(b->left, c, perr, type, rules); + t = propagate_types(b->right, c, perr, t, rules); + if (t && t->test == NULL) + type_err(c, "error: \"??\" requires a testable value, not %1", + prog, t, 0, NULL); + return t; + case Bracket: return propagate_types(b->right, c, perr, type, 0); @@ -3882,6 +3921,20 @@ parentheses around an expression converts it into a Term, printf("Unsupported suffix: %.*s\n", tx.len, tx.txt); // UNTESTED break; + case Test: + right = interp_exec(c, b->right, &rtype); + rvtype = Tbool; + rv.bool = !!rtype->test(rtype, &right); + break; + case Choose: + left = interp_exec(c, b->left, <ype); + if (ltype->test(ltype, &left)) { + rv = left; + rvtype = ltype; + ltype = NULL; + } else + rv = interp_exec(c, b->right, &rvtype); + break; ###### value functions