Browse Source

Infix and Postfix procedure calls

gingerBill 9 years ago
parent
commit
975705f1fc
9 changed files with 154 additions and 79 deletions
  1. 11 11
      examples/basic.odin
  2. 14 9
      examples/demo.odin
  3. 1 1
      examples/game.odin
  4. 13 7
      examples/math.odin
  5. 37 37
      examples/win32.odin
  6. 17 2
      src/checker/expr.cpp
  7. 26 3
      src/parser.cpp
  8. 5 5
      src/string.cpp
  9. 30 4
      src/tokenizer.cpp

+ 11 - 11
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-- {

+ 14 - 9
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.
 	}
 

+ 1 - 1
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 {

+ 13 - 7
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)}; }

+ 37 - 37
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_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_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_LWIN       :: 0x5B;
 VK_RWIN       :: 0x5C;

+ 17 - 2
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;

+ 26 - 3
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);

+ 5 - 5
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;
 		}

+ 30 - 4
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;
 				}
 			}