Buffer :: #type []void;
+range :: struct {
+ low : i32;
+ high : i32;
+ step : i32 = 1;
+}
+
null :: cast(rawptr) 0;
// ---------------------------------
- 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
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,
Binary_Op_Assign_End = 32,
Binary_Op_Pipe = 33,
+ Binary_Op_Range = 34,
} BinaryOp;
typedef enum OnyxIntrinsic {
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;
Token_Type_Shr_Equal,
Token_Type_Sar_Equal,
+ Token_Type_Dot_Dot,
+
Token_Type_Symbol,
Token_Type_Literal_String,
Token_Type_Literal_Integer,
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);
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);
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 },
}
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;
+ }
+}
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);
actual->type = actual->value->type;
actual->value->flags |= Ast_Flag_Function_Used;
}
-
+
actual = (AstArgument *) actual->next;
arg_idx++;
}
// NOTE: Not a binary op
*pbinop = (AstBinaryOp *) ast_reduce(semstate.node_allocator, (AstTyped *) binop);
}
-
+
return 0;
}
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));
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) {
return 1;
}
}
-
+
return 0;
}
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);
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;
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));
}
return nn;
-}
\ No newline at end of file
+}
"<<=",
">>=",
">>>=",
+ "..",
"TOKEN_TYPE_SYMBOL",
"TOKEN_TYPE_LITERAL_STRING",
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;
}
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;
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;
}
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);
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);
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);
}
}
-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) {
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;
if (param->default_value != NULL) {
symres_expression(¶m->default_value);
if (onyx_has_errors()) return;
-
+
if (check_expression(¶m->default_value)) return;
}
}
"ARRAY_ACCESS",
"SLICE",
"FIELD_ACCESS",
- "UFC",
+ "PIPE",
+ "RANGE",
"SIZE OF",
"ALIGN OF",
"FILE CONTENTS",
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;
}
}