From: Brendan Hansen Date: Fri, 4 Sep 2020 03:18:40 +0000 (-0500) Subject: added ranges; will replace for loop and slice syntax soon X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=d4a9ef21b941792c7d11ee3e8791de8f052f8be4;p=onyx.git added ranges; will replace for loop and slice syntax soon --- diff --git a/core/builtin.onyx b/core/builtin.onyx index f8b1d2dc..b07fe7d6 100644 --- a/core/builtin.onyx +++ b/core/builtin.onyx @@ -5,6 +5,12 @@ cstring :: #type ^u8; Buffer :: #type []void; +range :: struct { + low : i32; + high : i32; + step : i32 = 1; +} + null :: cast(rawptr) 0; // --------------------------------- diff --git a/docs/plan b/docs/plan index ba6b114e..610ee4a6 100644 --- a/docs/plan +++ b/docs/plan @@ -237,6 +237,9 @@ HOW: - Removes the argument from the list and replaces the function with the baked function + [ ] Add SIMD intrinsics + - This also requires adding the v128 SIMD type + [ ] Put type info in data section so it is runtime accessible - type name - size diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 34537780..74747d84 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -125,7 +125,8 @@ typedef enum AstKind { Ast_Kind_Array_Access, Ast_Kind_Slice, Ast_Kind_Field_Access, - Ast_Kind_Ufc, + Ast_Kind_Pipe, + Ast_Kind_Range, Ast_Kind_Size_Of, Ast_Kind_Align_Of, Ast_Kind_File_Contents, @@ -225,6 +226,7 @@ typedef enum BinaryOp { Binary_Op_Assign_End = 32, Binary_Op_Pipe = 33, + Binary_Op_Range = 34, } BinaryOp; typedef enum OnyxIntrinsic { @@ -581,6 +583,7 @@ extern AstNode builtin_package_node; extern AstNumLit builtin_heap_start; extern AstGlobal builtin_stack_top; extern AstType *builtin_string_type; +extern AstType *builtin_range_type; typedef struct BuiltinSymbol { char* package; diff --git a/include/onyxlex.h b/include/onyxlex.h index 21d4b3a0..58cd343e 100644 --- a/include/onyxlex.h +++ b/include/onyxlex.h @@ -60,6 +60,8 @@ typedef enum TokenType { Token_Type_Shr_Equal, Token_Type_Sar_Equal, + Token_Type_Dot_Dot, + Token_Type_Symbol, Token_Type_Literal_String, Token_Type_Literal_Integer, diff --git a/onyx b/onyx index bfe7d9cd..4d064dbd 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/poly_test.onyx b/progs/poly_test.onyx index b4a68d62..80de2d0d 100644 --- a/progs/poly_test.onyx +++ b/progs/poly_test.onyx @@ -61,14 +61,31 @@ soa_deinit :: proc (s: ^SOA) { array_free(^s.b); } +get_range :: proc (arr: ^[..] $T) -> range { + return 0 .. arr.count; +} + +print_range :: proc (r: range) #add_overload print { + print(r.low); + print(" to "); + print(r.high); + print(" by "); + print(r.step); + print("\n"); +} + main :: proc (args: [] cstring) { res := compose(5, proc (x: i32) -> i32 do return x * 3;, proc (x: i32) -> i32 do return x + 5;); print(res); + print("\n"); s : SOA; soa_init(^s); - defer soa_deinit(^s); + defer { + print("Clearing SOA...\n"); + soa_deinit(^s); + } print_arr_details(^s.a); print_arr_details(^s.b); @@ -78,6 +95,9 @@ main :: proc (args: [] cstring) { array_push(^s.b, 3l * cast(i64) i); } + r := ^s.a |> get_range(); + print(r); + array_sort(^s.a, cmp_dec); array_sort(^s.b, cmp_asc); diff --git a/src/onyxbuiltins.c b/src/onyxbuiltins.c index b1f4e487..4085e062 100644 --- a/src/onyxbuiltins.c +++ b/src/onyxbuiltins.c @@ -24,7 +24,9 @@ static OnyxToken builtin_heap_start_token = { Token_Type_Symbol, 12, "__heap_sta static OnyxToken builtin_stack_top_token = { Token_Type_Symbol, 11, "__stack_top ", { 0 } }; AstNumLit builtin_heap_start = { Ast_Kind_NumLit, Ast_Flag_Const, &builtin_heap_start_token, NULL, (AstType *) &basic_type_rawptr, NULL, 0 }; AstGlobal builtin_stack_top = { Ast_Kind_Global, Ast_Flag_Const | Ast_Flag_Global_Stack_Top, &builtin_stack_top_token, NULL, (AstType *) &basic_type_rawptr, NULL }; + AstType *builtin_string_type; +AstType *builtin_range_type; const BuiltinSymbol builtin_symbols[] = { { NULL, "void", (AstNode *) &basic_type_void }, @@ -69,9 +71,16 @@ void initialize_builtins(bh_allocator a, ProgramInfo* prog) { } Package* p = program_info_package_lookup_or_create(prog, "builtin", prog->global_scope, a); + builtin_string_type = (AstType *) symbol_raw_resolve(p->scope, "string"); if (builtin_string_type == NULL) { onyx_report_error((OnyxFilePos) { 0 }, "'string' struct not found in builtin package."); return; } -} \ No newline at end of file + + builtin_range_type = (AstType *) symbol_raw_resolve(p->scope, "range"); + if (builtin_range_type == NULL) { + onyx_report_error((OnyxFilePos) { 0 }, "'range' struct not found in builtin package."); + return; + } +} diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 0d0dfe16..8204f0d6 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -23,6 +23,7 @@ CHECK(dereference, AstDereference* deref); CHECK(array_access, AstArrayAccess* expr); CHECK(slice, AstSlice* sl); CHECK(field_access, AstFieldAccess** pfield); +CHECK(range_literal, AstBinaryOp** range); CHECK(size_of, AstSizeOf* so); CHECK(align_of, AstAlignOf* ao); CHECK(global, AstGlobal* global); @@ -331,7 +332,7 @@ b32 check_call(AstCall* call) { actual->type = actual->value->type; actual->value->flags |= Ast_Flag_Function_Used; } - + actual = (AstArgument *) actual->next; arg_idx++; } @@ -587,7 +588,7 @@ b32 check_binaryop_compare(AstBinaryOp** pbinop) { // NOTE: Not a binary op *pbinop = (AstBinaryOp *) ast_reduce(semstate.node_allocator, (AstTyped *) binop); } - + return 0; } @@ -946,6 +947,52 @@ b32 check_field_access(AstFieldAccess** pfield) { return 0; } +b32 check_range_literal(AstBinaryOp** prange) { + AstBinaryOp* range = *prange; + if (check_expression(&range->left)) return 1; + if (check_expression(&range->right)) return 1; + + Type* expected_range_type = type_build_from_ast(semstate.node_allocator, builtin_range_type); + StructMember smem; + + type_lookup_member(expected_range_type, "low", &smem); + if (!types_are_compatible(range->left->type, smem.type)) { + onyx_report_error(range->token->pos, "Expected left side of range to be a 32-bit integer."); + return 1; + } + + type_lookup_member(expected_range_type, "high", &smem); + if (!types_are_compatible(range->right->type, smem.type)) { + onyx_report_error(range->token->pos, "Expected right side of range to be a 32-bit integer."); + return 1; + } + + // NOTE: Implicitly converting this to a struct literal because that makes the + // WASM generation easier and more robust for return a range from a procedure + // and the like. This could be improved as struct literals are made more throughout + // the code base. + // - brendanfh, 2020/09/03 + AstStructLiteral* rsl = onyx_ast_node_new(semstate.node_allocator, sizeof(AstStructLiteral), Ast_Kind_Struct_Literal); + bh_arr_new(global_heap_allocator, rsl->values, 3); + + bh_arr_push(rsl->values, range->left); + bh_arr_push(rsl->values, range->right); + + // HACK: This relies on the third member of the 'range' struct to exist, be the step, + // and have an intial_value. + AstStructMember* step_member = ((AstStructType *) builtin_range_type)->members[2]; + if (check_expression(&step_member->initial_value)) return 1; + bh_arr_push(rsl->values, step_member->initial_value); + + rsl->token = range->token; + rsl->type = expected_range_type; + + // NOTE: Not a binary op + *prange = (AstBinaryOp *) rsl; + + return 0; +} + b32 check_size_of(AstSizeOf* so) { so->size = type_size_of(type_build_from_ast(semstate.allocator, so->so_type)); @@ -998,6 +1045,7 @@ b32 check_expression(AstTyped** pexpr) { case Ast_Kind_Field_Access: retval = check_field_access((AstFieldAccess **) pexpr); break; case Ast_Kind_Size_Of: retval = check_size_of((AstSizeOf *) expr); break; case Ast_Kind_Align_Of: retval = check_align_of((AstAlignOf *) expr); break; + case Ast_Kind_Range: retval = check_range_literal((AstBinaryOp **) pexpr); break; case Ast_Kind_Global: if (expr->type == NULL) { @@ -1252,7 +1300,7 @@ b32 check_memres(AstMemRes* memres) { return 1; } } - + return 0; } diff --git a/src/onyxclone.c b/src/onyxclone.c index 1f5049af..c0c32c93 100644 --- a/src/onyxclone.c +++ b/src/onyxclone.c @@ -71,7 +71,8 @@ static inline i32 ast_kind_to_size(AstNode* node) { case Ast_Kind_Array_Access: return sizeof(AstArrayAccess); case Ast_Kind_Slice: return sizeof(AstSlice); case Ast_Kind_Field_Access: return sizeof(AstFieldAccess); - case Ast_Kind_Ufc: return sizeof(AstBinaryOp); + case Ast_Kind_Pipe: return sizeof(AstBinaryOp); + case Ast_Kind_Range: return sizeof(AstBinaryOp); case Ast_Kind_Size_Of: return sizeof(AstSizeOf); case Ast_Kind_Align_Of: return sizeof(AstAlignOf); case Ast_Kind_File_Contents: return sizeof(AstFileContents); @@ -223,7 +224,7 @@ AstNode* ast_clone(bh_allocator a, void* n) { if (((AstIfWhile *) nn)->assignment) ((AstIfWhile *) nn)->assignment->left = (AstTyped *) ((AstIfWhile *) nn)->local; - ((AstIfWhile *) nn)->cond = (AstTyped *) ast_clone(a, ((AstIfWhile *) node)->cond); + ((AstIfWhile *) nn)->cond = (AstTyped *) ast_clone(a, ((AstIfWhile *) node)->cond); ((AstIfWhile *) nn)->true_stmt = (AstBlock *) ast_clone(a, ((AstIfWhile *) node)->true_stmt); ((AstIfWhile *) nn)->false_stmt = (AstBlock *) ast_clone(a, ((AstIfWhile *) node)->false_stmt); break; @@ -239,7 +240,7 @@ AstNode* ast_clone(bh_allocator a, void* n) { dw->expr = (AstTyped *) ast_clone(a, sw->expr); dw->default_case = (AstBlock *) ast_clone(a, sw->default_case); - + dw->cases = NULL; bh_arr_new(global_heap_allocator, dw->cases, bh_arr_length(sw->cases)); @@ -314,4 +315,4 @@ AstNode* ast_clone(bh_allocator a, void* n) { } return nn; -} \ No newline at end of file +} diff --git a/src/onyxlex.c b/src/onyxlex.c index 4f6945db..d5a0a0fe 100644 --- a/src/onyxlex.c +++ b/src/onyxlex.c @@ -57,6 +57,7 @@ static const char* token_type_names[] = { "<<=", ">>=", ">>>=", + "..", "TOKEN_TYPE_SYMBOL", "TOKEN_TYPE_LITERAL_STRING", @@ -366,13 +367,14 @@ whitespace_skipped: break; default: - LITERAL_TOKEN("^=", 0, Token_Type_Xor_Equal); LITERAL_TOKEN("==", 0, Token_Type_Equal_Equal); LITERAL_TOKEN("!=", 0, Token_Type_Not_Equal); LITERAL_TOKEN("+=", 0, Token_Type_Plus_Equal); LITERAL_TOKEN("*=", 0, Token_Type_Star_Equal); + LITERAL_TOKEN("^=", 0, Token_Type_Xor_Equal); LITERAL_TOKEN("/=", 0, Token_Type_Fslash_Equal); LITERAL_TOKEN("%=", 0, Token_Type_Percent_Equal); + LITERAL_TOKEN("..", 0, Token_Type_Dot_Dot); break; } diff --git a/src/onyxparser.c b/src/onyxparser.c index 3c511d70..70603f3e 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -612,6 +612,7 @@ static inline i32 get_precedence(BinaryOp kind) { case Binary_Op_Assign_Sar: return 1; case Binary_Op_Pipe: return 2; + case Binary_Op_Range: return 2; case Binary_Op_Bool_And: return 3; case Binary_Op_Bool_Or: return 3; @@ -716,6 +717,7 @@ static AstTyped* parse_expression(OnyxParser* parser) { case Token_Type_Sar_Equal: bin_op_kind = Binary_Op_Assign_Sar; break; case Token_Type_Pipe: bin_op_kind = Binary_Op_Pipe; break; + case Token_Type_Dot_Dot: bin_op_kind = Binary_Op_Range; break; default: goto expression_done; } @@ -724,16 +726,19 @@ static AstTyped* parse_expression(OnyxParser* parser) { consume_token(parser); AstBinaryOp* bin_op; - if (bin_op_kind != Binary_Op_Pipe) { - bin_op = make_node(AstBinaryOp, Ast_Kind_Binary_Op); - bin_op->operation = bin_op_kind; - bin_op->token = bin_op_tok; + if (bin_op_kind == Binary_Op_Pipe) { + bin_op = make_node(AstBinaryOp, Ast_Kind_Pipe); + + } else if (bin_op_kind == Binary_Op_Range) { + bin_op = make_node(AstBinaryOp, Ast_Kind_Range); } else { - bin_op = make_node(AstBinaryOp, Ast_Kind_Ufc); - bin_op->token = bin_op_tok; + bin_op = make_node(AstBinaryOp, Ast_Kind_Binary_Op); } + bin_op->token = bin_op_tok; + bin_op->operation = bin_op_kind; + while ( !bh_arr_is_empty(tree_stack) && get_precedence(bh_arr_last(tree_stack)->operation) >= get_precedence(bin_op_kind)) bh_arr_pop(tree_stack); @@ -1209,12 +1214,11 @@ static AstType* parse_type(OnyxParser* parser) { if (parser->curr->type == ']') { new = make_node(AstSliceType, Ast_Kind_Slice_Type); new->token = open_bracket; - - } else if (parser->curr->type == '.') { + + } else if (parser->curr->type == Token_Type_Dot_Dot) { new = make_node(AstDynArrType, Ast_Kind_DynArr_Type); new->token = open_bracket; consume_token(parser); - expect_token(parser, '.'); } else { new = make_node(AstArrayType, Ast_Kind_Array_Type); @@ -1531,7 +1535,7 @@ static AstFunction* parse_function_definition(OnyxParser* parser) { if (func_def->overloaded_function != NULL) { onyx_report_error(parser->curr->pos, "cannot have multiple #add_overload directives on a single procedure."); expect_token(parser, Token_Type_Symbol); - + } else { AstNode* sym_node = make_node(AstNode, Ast_Kind_Symbol); sym_node->token = expect_token(parser, Token_Type_Symbol); diff --git a/src/onyxsymres.c b/src/onyxsymres.c index ece7115f..4871c6d3 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -182,31 +182,31 @@ static void symres_field_access(AstFieldAccess** fa) { } } -static void symres_ufc(AstBinaryOp** ufc) { - AstCall* call_node = (AstCall *) (*ufc)->right; +static void symres_pipe(AstBinaryOp** pipe) { + AstCall* call_node = (AstCall *) (*pipe)->right; symres_expression((AstTyped **) &call_node); - symres_expression(&(*ufc)->left); + symres_expression(&(*pipe)->left); if (call_node->kind != Ast_Kind_Call) { - onyx_report_error((*ufc)->token->pos, "universal function call expected call on right side"); + onyx_report_error((*pipe)->token->pos, "universal function call expected call on right side"); return; } - if ((*ufc)->left == NULL) return; + if ((*pipe)->left == NULL) return; AstArgument* implicit_arg = onyx_ast_node_new(semstate.node_allocator, sizeof(AstArgument), Ast_Kind_Argument); - implicit_arg->token = (*ufc)->left->token; - implicit_arg->value = (*ufc)->left; + implicit_arg->token = (*pipe)->left->token; + implicit_arg->value = (*pipe)->left; implicit_arg->next = (AstNode *) call_node->arguments; call_node->arguments = implicit_arg; call_node->arg_count++; - call_node->next = (*ufc)->next; + call_node->next = (*pipe)->next; // NOTE: Not a BinaryOp node - *ufc = (AstBinaryOp *) call_node; + *pipe = (AstBinaryOp *) call_node; } static void symres_unaryop(AstUnaryOp** unaryop) { @@ -297,15 +297,22 @@ static void symres_expression(AstTyped** expr) { case Ast_Kind_Address_Of: symres_expression(&((AstAddressOf *)(*expr))->expr); break; case Ast_Kind_Dereference: symres_expression(&((AstDereference *)(*expr))->expr); break; case Ast_Kind_Field_Access: symres_field_access((AstFieldAccess **) expr); break; - case Ast_Kind_Ufc: symres_ufc((AstBinaryOp **) expr); break; + case Ast_Kind_Pipe: symres_pipe((AstBinaryOp **) expr); break; case Ast_Kind_Size_Of: symres_size_of((AstSizeOf *)*expr); break; case Ast_Kind_Align_Of: symres_align_of((AstAlignOf *)*expr); break; + case Ast_Kind_Range: + symres_expression(&((AstBinaryOp *)(*expr))->left); + symres_expression(&((AstBinaryOp *)(*expr))->right); + + (*expr)->type_node = symres_type(builtin_range_type); + break; + case Ast_Kind_Function: case Ast_Kind_NumLit: (*expr)->type_node = symres_type((*expr)->type_node); break; - + case Ast_Kind_StrLit: (*expr)->type_node = symres_type(builtin_string_type); break; @@ -462,7 +469,7 @@ void symres_function(AstFunction* func) { if (param->default_value != NULL) { symres_expression(¶m->default_value); if (onyx_has_errors()) return; - + if (check_expression(¶m->default_value)) return; } } diff --git a/src/onyxutils.c b/src/onyxutils.c index 9c057fd2..1b330fcb 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -69,7 +69,8 @@ static const char* ast_node_names[] = { "ARRAY_ACCESS", "SLICE", "FIELD_ACCESS", - "UFC", + "PIPE", + "RANGE", "SIZE OF", "ALIGN OF", "FILE CONTENTS", @@ -326,7 +327,7 @@ AstTyped* ast_reduce(bh_allocator a, AstTyped* node) { case Ast_Kind_Binary_Op: return (AstTyped *) ast_reduce_binop(a, (AstBinaryOp *) node); case Ast_Kind_Unary_Op: return (AstTyped *) ast_reduce_unaryop(a, (AstUnaryOp *) node); case Ast_Kind_NumLit: return node; - default: return NULL; + default: return NULL; } }