diff --git a/examples/basic.odin b/examples/basic.odin index 401754c57..e9ffe5591 100644 --- a/examples/basic.odin +++ b/examples/basic.odin @@ -53,8 +53,8 @@ print_rune :: proc(r: rune) { print_string(str); } -print_space :: proc() { print_rune(' '); } -print_nl :: proc() { print_rune('\n'); } +print_space :: proc() { print_rune($ $); } +print_nl :: proc() { print_rune($\n$); } print_int :: proc(i: int) { print_int_base(i, 10); @@ -70,7 +70,7 @@ print_int_base :: proc(i, base: int) { i = -i; } if i == 0 { - buf[len] = '0'; + buf[len] = $0$; len++; } for i > 0 { @@ -80,7 +80,7 @@ print_int_base :: proc(i, base: int) { } if negative { - buf[len] = '-'; + buf[len] = $-$; len++; } @@ -89,7 +89,7 @@ print_int_base :: proc(i, base: int) { } print_uint :: proc(i: uint) { - print__uint(i, 10, 0, ' '); + print__uint(i, 10, 0, $ $); } print__uint :: proc(i, base: uint, min_width: int, pad_char: byte) { NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"; @@ -97,7 +97,7 @@ print__uint :: proc(i, base: uint, min_width: int, pad_char: byte) { buf: [65]byte; len := 0; if i == 0 { - buf[len] = '0'; + buf[len] = $0$; len++; } for i > 0 { @@ -119,18 +119,18 @@ print_bool :: proc(b : bool) { else { print_string("false"); } } -print_pointer :: proc(p: rawptr) #inline { print__uint(p as uint, 16, 0, ' '); } +print_pointer :: proc(p: rawptr) #inline { print__uint(p as uint, 16, 0, $ $); } print_f32 :: proc(f: f32) #inline { print__f64(f as f64, 7); } print_f64 :: proc(f: f64) #inline { print__f64(f, 10); } print__f64 :: proc(f: f64, decimal_places: int) { if f == 0 { - print_rune('0'); + print_rune($0$); return; } if f < 0 { - print_rune('-'); + print_rune($-$); f = -f; } @@ -140,7 +140,7 @@ print__f64 :: proc(f: f64, decimal_places: int) { buf: [22]byte; len := 0; if i == 0 { - buf[len] = '0'; + buf[len] = $0$; len++; } for i > 0 { @@ -156,7 +156,7 @@ print__f64 :: proc(f: f64, decimal_places: int) { print_u64(i); f -= i as f64; - print_rune('.'); + print_rune($.$); mult := 10.0; for decimal_places := 6; decimal_places >= 0; decimal_places-- { diff --git a/examples/demo.odin b/examples/demo.odin index 2388e0fe4..f5afa04fc 100644 --- a/examples/demo.odin +++ b/examples/demo.odin @@ -11,7 +11,7 @@ main :: proc() { // types(); // data_control(); - run_game(); + // run_game(); } hellope :: proc() -> int { @@ -118,7 +118,7 @@ procedures :: proc() { return x + y; } print_int(add(3, 4)); // 7 - print_rune('\n'); + print_nl(); add_v2 :: proc(x, y: int) -> int { return x + y; @@ -152,6 +152,11 @@ procedures :: proc() { proc2 :: proc(a, b: int) #no_inline { print_int(a + b); } + + print_int(3 'add' 4); // Infix style + print_nl(); + print_int(12 'fibonacci); // Postfix style + print_nl(); } @@ -175,7 +180,7 @@ constants :: proc() { c := DIFF; } -nl :: proc() { print_rune('\n'); } +nl :: proc() { print_nl(); } types :: proc() { @@ -390,8 +395,8 @@ types :: proc() { // FORENOTE: 5 * h was originally allowed but it was an edge case in the // compiler I didn't think it was enough to justify have it it. - print_f32(i[0]); print_rune(','); - print_f32(i[1]); print_rune('\n'); + print_f32(i[0]); print_rune($,$); + print_f32(i[1]); print_nl(); } @@ -452,12 +457,12 @@ void main() { }`; - hearts1 := '💕'; - hearts2 := '\U0001f495'; // 32 bit + hearts1 := $💕$; + hearts2 := $\U0001f495$; // 32 bit hearts3 := "\xf0\x9f\x92\x95"; // Note it's a string, should I allow untyped string -> untyped rune casts? - 㐒 := '㐒'; - 㐒16 := '\u4db5'; // 16 bit + 㐒 := $㐒$; + 㐒16 := $\u4db5$; // 16 bit // String ideas "nicked" from Go, so far. I think I might change how some of it works later. } diff --git a/examples/game.odin b/examples/game.odin index cd1036846..31b6eecc0 100644 --- a/examples/game.odin +++ b/examples/game.odin @@ -2,7 +2,7 @@ #load "opengl.odin" #load "math.odin" -TWO_HEARTS :: '💕'; +TWO_HEARTS :: $💕$; win32_perf_count_freq := GetQueryPerformanceFrequency(); time_now :: proc() -> f64 { diff --git a/examples/math.odin b/examples/math.odin index af3c8a6d4..0345fb65e 100644 --- a/examples/math.odin +++ b/examples/math.odin @@ -61,7 +61,7 @@ floor :: proc(x: f32) -> f32 { } return (x-0.5) as int as f32; } -ceil :: proc(x: f32) -> f32 { +ceil :: proc(x: f32) -> f32 { if x < 0 { return x as int as f32; } @@ -91,14 +91,20 @@ to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / MATH_TAU; } -vec2_dot :: proc(a, b: Vec2) -> f32 { c := a*b; return c[0] + c[1]; } -vec3_dot :: proc(a, b: Vec3) -> f32 { c := a*b; return c[0] + c[1] + c[2]; } -vec4_dot :: proc(a, b: Vec4) -> f32 { c := a*b; return c[0] + c[1] + c[2] + c[3]; } +dot2 :: proc(a, b: Vec2) -> f32 { c := a*b; return c[0] + c[1]; } +dot3 :: proc(a, b: Vec3) -> f32 { c := a*b; return c[0] + c[1] + c[2]; } +dot4 :: proc(a, b: Vec4) -> f32 { c := a*b; return c[0] + c[1] + c[2] + c[3]; } + +cross :: proc(x, y: Vec3) -> Vec3 { + a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1); + b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0); + return a - b; +} -vec2_mag :: proc(v: Vec2) -> f32 { return fsqrt(vec2_dot(v, v)); } -vec3_mag :: proc(v: Vec3) -> f32 { return fsqrt(vec3_dot(v, v)); } -vec4_mag :: proc(v: Vec4) -> f32 { return fsqrt(vec4_dot(v, v)); } +vec2_mag :: proc(v: Vec2) -> f32 { return fsqrt(v 'dot2' v); } +vec3_mag :: proc(v: Vec3) -> f32 { return fsqrt(v 'dot3' v); } +vec4_mag :: proc(v: Vec4) -> f32 { return fsqrt(v 'dot4' v); } vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)}; } vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; } diff --git a/examples/win32.odin b/examples/win32.odin index 2a8beb450..5e83f5bb0 100644 --- a/examples/win32.odin +++ b/examples/win32.odin @@ -291,43 +291,43 @@ VK_INSERT :: 0x2D; VK_DELETE :: 0x2E; VK_HELP :: 0x2F; -VK_0 :: '0'; -VK_1 :: '1'; -VK_2 :: '2'; -VK_3 :: '3'; -VK_4 :: '4'; -VK_5 :: '5'; -VK_6 :: '6'; -VK_7 :: '7'; -VK_8 :: '8'; -VK_9 :: '9'; +VK_0 :: $0$; +VK_1 :: $1$; +VK_2 :: $2$; +VK_3 :: $3$; +VK_4 :: $4$; +VK_5 :: $5$; +VK_6 :: $6$; +VK_7 :: $7$; +VK_8 :: $8$; +VK_9 :: $9$; -VK_A :: 'A'; -VK_B :: 'B'; -VK_C :: 'C'; -VK_D :: 'D'; -VK_E :: 'E'; -VK_F :: 'F'; -VK_G :: 'G'; -VK_H :: 'H'; -VK_I :: 'I'; -VK_J :: 'J'; -VK_K :: 'K'; -VK_L :: 'L'; -VK_M :: 'M'; -VK_N :: 'N'; -VK_O :: 'O'; -VK_P :: 'P'; -VK_Q :: 'Q'; -VK_R :: 'R'; -VK_S :: 'S'; -VK_T :: 'T'; -VK_U :: 'U'; -VK_V :: 'V'; -VK_W :: 'W'; -VK_X :: 'X'; -VK_Y :: 'Y'; -VK_Z :: 'Z'; +VK_A :: $A$; +VK_B :: $B$; +VK_C :: $C$; +VK_D :: $D$; +VK_E :: $E$; +VK_F :: $F$; +VK_G :: $G$; +VK_H :: $H$; +VK_I :: $I$; +VK_J :: $J$; +VK_K :: $K$; +VK_L :: $L$; +VK_M :: $M$; +VK_N :: $N$; +VK_O :: $O$; +VK_P :: $P$; +VK_Q :: $Q$; +VK_R :: $R$; +VK_S :: $S$; +VK_T :: $T$; +VK_U :: $U$; +VK_V :: $V$; +VK_W :: $W$; +VK_X :: $X$; +VK_Y :: $Y$; +VK_Z :: $Z$; VK_LWIN :: 0x5B; VK_RWIN :: 0x5C; diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index bd317c08d..63a87f3f5 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -1386,7 +1386,6 @@ Entity *lookup_field(Type *type, AstNode *field_node, isize *index = NULL) { } } break; - break; // TODO(bill): Other types and extra "hidden" fields (e.g. introspection stuff) // TODO(bill): Allow for access of field through index? e.g. `x.3` will get member of index 3 // Or is this only suitable if tuples are first-class? @@ -1402,7 +1401,14 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) { AstNode *op_expr = se->expr; AstNode *selector = se->selector; if (selector) { - Entity *entity = lookup_field(operand->type, selector); + Entity *entity = NULL; + if (is_type_enum(operand->type)) { + if (operand->mode == Addressing_Type) { + entity = lookup_field(operand->type, selector); + } + } else { + entity = lookup_field(operand->type, selector); + } if (entity == NULL) { gbString op_str = expr_to_string(op_expr); gbString sel_str = expr_to_string(selector); @@ -2631,6 +2637,15 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, "}"); case_end; + case_ast_node(et, EnumType, node); + str = gb_string_appendc(str, "enum "); + if (et->base_type != NULL) { + str = write_expr_to_string(str, et->base_type); + str = gb_string_appendc(str, " "); + } + str = gb_string_appendc(str, "{"); + str = gb_string_appendc(str, "}"); + case_end; } return str; diff --git a/src/parser.cpp b/src/parser.cpp index beb0eb49f..6fb491557 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -81,6 +81,12 @@ enum VarDeclTag { VarDeclTag_thread_local = GB_BIT(0), }; +enum CallExprKind { + CallExpr_Normal, + CallExpr_UnaryOp, + CallExpr_BinaryOp, +}; + #define AST_NODE_KINDS \ AST_NODE_KIND(Invalid, struct{}) \ AST_NODE_KIND(BasicLit, Token) \ @@ -112,6 +118,7 @@ AST_NODE_KIND(_ExprBegin, struct{}) \ AstNode *proc, *arg_list; \ isize arg_list_count; \ Token open, close; \ + CallExprKind kind; \ }) \ AST_NODE_KIND(SliceExpr, struct { \ AstNode *expr; \ @@ -1186,6 +1193,16 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) { b32 loop = true; while (loop) { switch (f->cursor[0].kind) { + + case Token_CustomUnaryOp: { + Token op = expect_token(f, Token_CustomUnaryOp); + if (lhs) { + // TODO(bill): Handle this + } + AstNode *proc = make_ident(f, op); + operand = make_call_expr(f, proc, operand, 1, ast_node_token(operand), op); + } break; + case Token_OpenParen: { if (lhs) { // TODO(bill): Handle this shit! Is this even allowed in this language?! @@ -1354,8 +1371,14 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) { ast_file_err(f, op, "Expected expression on the right hand side of the binary operator"); } } - expression = make_binary_expr(f, op, expression, right); + if (op.kind == Token_CustomBinaryOp) { + AstNode *proc = make_ident(f, op); + expression->next = right; + expression = make_call_expr(f, proc, expression, 2, ast_node_token(expression), ast_node_token(right)); + } else { + expression = make_binary_expr(f, op, expression, right); + } } } return expression; @@ -1638,7 +1661,7 @@ AstNode *parse_identifier_or_type(AstFile *f) { Token token = expect_token(f, Token_enum); AstNode *base_type = NULL; Token open, close; - + if (f->cursor[0].kind != Token_OpenBrace) { base_type = parse_type(f); } @@ -1669,7 +1692,7 @@ AstNode *parse_identifier_or_type(AstFile *f) { close = expect_token(f, Token_CloseBrace); return make_enum_type(f, token, base_type, root, field_count); - } + } case Token_proc: return parse_proc_type(f, NULL); diff --git a/src/string.cpp b/src/string.cpp index 1581feab9..8b5e3aa4b 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -82,7 +82,7 @@ b32 string_contains_char(String s, u8 c) { b32 unquote_char(String s, u8 quote, Rune *rune, b32 *multiple_bytes, String *tail_string) { if (s.text[0] == quote && - (quote == '\'' || quote == '"')) { + (quote == '$' || quote == '"')) { return false; } else if (s.text[0] >= 0x80) { Rune r = -1; @@ -116,7 +116,7 @@ b32 unquote_char(String s, u8 quote, Rune *rune, b32 *multiple_bytes, String *ta case '\\': *rune = '\\'; break; - case '\'': + case '$': case '"': if (c != quote) { return false; @@ -210,7 +210,7 @@ i32 unquote_string(gbAllocator a, String *s_) { *s_ = s; return 1; } - if (quote != '"' && quote != '\'') + if (quote != '"' && quote != '$') return 0; if (string_contains_char(s, '\n')) @@ -220,7 +220,7 @@ i32 unquote_string(gbAllocator a, String *s_) { if (quote == '"') { *s_ = s; return 1; - } else if (quote == '\'') { + } else if (quote == '$') { Rune r = GB_RUNE_INVALID; isize size = gb_utf8_decode(s.text, s.len, &r); if ((size == s.len) && (r != -1 || size != 1)) { @@ -254,7 +254,7 @@ i32 unquote_string(gbAllocator a, String *s_) { offset += size; } - if (quote == '\'' && s.len != 0) { + if (quote == '$' && s.len != 0) { gb_free(a, buf); return 0; } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 68c8918d0..82c98e256 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -30,6 +30,9 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \ \ TOKEN_KIND(Token_as, "as"), \ TOKEN_KIND(Token_transmute, "transmute"), \ +\ + TOKEN_KIND(Token_CustomUnaryOp, "custom unary op"), \ + TOKEN_KIND(Token_CustomBinaryOp, "custom binary op"), \ \ TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \ TOKEN_KIND(Token_AddEq, "+="), \ @@ -199,9 +202,11 @@ i32 token_precedence(Token t) { case Token_Shl: case Token_Shr: return 5; + case Token_CustomBinaryOp: + return 6; case Token_as: case Token_transmute: - return 6; + return 7; } return 0; @@ -642,6 +647,27 @@ Token tokenizer_get_token(Tokenizer *t) { token.kind = Token_EOF; break; + case '\'': { + token.kind = Token_CustomUnaryOp; + while (rune_is_whitespace(t->curr_rune)) + advance_to_next_rune(t); + token.string.text = t->curr; + while (rune_is_letter(t->curr_rune) || rune_is_digit(t->curr_rune)) { + advance_to_next_rune(t); + } + token.string.len = t->curr - token.string.text; + + while (rune_is_whitespace(t->curr_rune)) + advance_to_next_rune(t); + + if (t->curr_rune == '\'') { + advance_to_next_rune(t); + token.kind = Token_CustomBinaryOp; + } + + return token; + } break; + case '`': // Raw String Literal case '"': // String Literal { @@ -684,7 +710,7 @@ Token tokenizer_get_token(Tokenizer *t) { } } break; - case '\'': { // Rune Literal + case '$': { // Rune Literal b32 valid = true; isize len = 0; token.kind = Token_Rune; @@ -696,11 +722,11 @@ Token tokenizer_get_token(Tokenizer *t) { break; } advance_to_next_rune(t); - if (r == '\'') + if (r == '$') break; len++; if (r == '\\') { - if (!scan_escape(t, '\'')) + if (!scan_escape(t, '$')) valid = false; } }