diff --git a/README.md b/README.md index 38cfc96..f423276 100644 --- a/README.md +++ b/README.md @@ -83,11 +83,9 @@ You only need to compile the build tool once. Afterwards just call `./bld.exe`. ## Further plans -My priority is to improve the C user API, harden the compiler, accommodate things that I didn't foresee and stuff like that. - -Sometime in the future I want to implement a bytecode backend so that the language can be used like Lua as a nice scripting language. - -I'm also considering the addition of overloaded procedures because it would greatly aid in writing macros. +- **My priority is to improve the C user API, harden the compiler, accommodate things that I didn't foresee and stuff like that.** +- I want to implement a bytecode backend (in the future) so that the language can be used like Lua. +- New features are of second priority unless they are small and important but additionally I'm considering the addition of overloaded procedures because it would greatly aid in writing macros. # Language overview @@ -438,6 +436,55 @@ test :: proc() { } ``` +## Arithmetic operators + +``` odin +arithmetic_operators :: proc() { + add := 1 + 2; + sub := 1 - 2; + mul := 1 * 2; + div := 1 / 2; + mod := 1 % 2; + + and := 1 && 2; + or := 1 || 2; + equals := 1 == 2; + not_equals := 1 != 2; + greater_then := 1 > 2; + greater_then_or_equal := 1 >= 2; + lesser_then := 1 < 2; + lesser_then_or_equal := 1 <= 2; + + left_shift := 1 >> 2; + right_shift := 1 << 2; + bit_or := 1 | 2; + bit_and := 1 & 2; + bit_xor := 1 ^ 2; + + not := !1; + negate := ~1; +} +``` + +## Arithmetic assignment operators + +``` odin +arithmetic_assign_operators :: proc() { + a := 1; + a /= 1; + a *= 1; + a %= 1; + a -= 1; + a += 1; + a &= 1; + a |= 1; + a ^= 1; + a <<= 1; + a >>= 1; +} +``` + + ## Defer statement A defer statement allows to postpone a certain action to the end of scope. For example - you might allocate memory and use defer just bellow your allocation to free the memory. This free will be deferred, it will happen a bit later. diff --git a/src/compiler/lib_compiler.h b/src/compiler/lib_compiler.h index ed213dc..35ae8c1 100644 --- a/src/compiler/lib_compiler.h +++ b/src/compiler/lib_compiler.h @@ -781,13 +781,13 @@ typedef enum { typedef struct { int left; int right; -} LC_BindingPower; +} LC_Precedence; typedef enum { - LC_Binding_Prefix, - LC_Binding_Infix, - LC_Binding_Postfix, -} LC_Binding; + LC_PrecedenceKind_Prefix, + LC_PrecedenceKind_Infix, + LC_PrecedenceKind_Postfix, +} LC_PrecedenceKind; typedef enum { LC_CmpRes_LT, @@ -828,12 +828,6 @@ struct LC_FileIter { X(struct) \ X(union) \ X(addptr) \ - X(and) \ - X(or) \ - X(bit_and) \ - X(bit_or) \ - X(bit_xor) \ - X(not ) \ X(true) \ X(false) @@ -1141,38 +1135,37 @@ LC_FUNCTION LC_Type *LC_StripPointer(LC_Type *type); LC_FUNCTION LC_AST *LC_ParseFile(LC_AST *package, char *filename, char *content, int line); LC_FUNCTION LC_AST *LC_ParseTokens(LC_AST *package, LC_Lex *x); -LC_FUNCTION LC_Parser LC_MakeParser(LC_Lex *x); -LC_FUNCTION LC_Parser *LC_MakeParserQuick(char *str); -LC_FUNCTION LC_Token *LC_Next(void); -LC_FUNCTION LC_Token *LC_Get(void); -LC_FUNCTION LC_Token *LC_GetI(int i); -LC_FUNCTION LC_Token *LC_Is(LC_TokenKind kind); -LC_FUNCTION LC_Token *LC_IsKeyword(LC_Intern intern); -LC_FUNCTION LC_Token *LC_Match(LC_TokenKind kind); -LC_FUNCTION LC_Token *LC_MatchKeyword(LC_Intern intern); -LC_FUNCTION LC_BindingPower LC_MakeBP(int left, int right); -LC_FUNCTION LC_BindingPower LC_GetBindingPower(LC_Binding binding, LC_TokenKind kind); -LC_FUNCTION LC_AST *LC_ParseExprEx(int min_bp); -LC_FUNCTION LC_AST *LC_ParseCompo(LC_Token *pos, LC_AST *left); -LC_FUNCTION LC_AST *LC_ParseExpr(void); -LC_FUNCTION LC_AST *LC_ParseProcType(LC_Token *pos); -LC_FUNCTION LC_AST *LC_ParseType(void); -LC_FUNCTION LC_AST *LC_ParseForStmt(LC_Token *pos); -LC_FUNCTION LC_AST *LC_ParseSwitchStmt(LC_Token *pos); -LC_FUNCTION LC_AST *LC_ParseStmt(bool check_semicolon); -LC_FUNCTION LC_AST *LC_ParseStmtBlock(int flags); -LC_FUNCTION LC_AST *LC_ParseProcDecl(LC_Token *name); -LC_FUNCTION LC_AST *LC_ParseStruct(LC_ASTKind kind, LC_Token *ident); -LC_FUNCTION LC_AST *LC_ParseTypedef(LC_Token *ident); -LC_FUNCTION LC_AST *LC_CreateNote(LC_Token *pos, LC_Intern ident); -LC_FUNCTION LC_AST *LC_ParseNote(void); -LC_FUNCTION LC_AST *LC_ParseNotes(void); -LC_FUNCTION bool LC_ResolveBuildIf(LC_AST *build_if); -LC_FUNCTION LC_AST *LC_ParseImport(void); -LC_FUNCTION LC_AST *LC_ParseDecl(LC_AST *file); -LC_FUNCTION bool LC_EatUntilNextValidDecl(void); -LC_FUNCTION bool LC_ParseHashBuildOn(LC_AST *n); -LC_FUNCTION LC_AST *LC_ParseFileEx(LC_AST *package); +LC_FUNCTION LC_Parser LC_MakeParser(LC_Lex *x); +LC_FUNCTION LC_Parser *LC_MakeParserQuick(char *str); +LC_FUNCTION LC_Token *LC_Next(void); +LC_FUNCTION LC_Token *LC_Get(void); +LC_FUNCTION LC_Token *LC_GetI(int i); +LC_FUNCTION LC_Token *LC_Is(LC_TokenKind kind); +LC_FUNCTION LC_Token *LC_IsKeyword(LC_Intern intern); +LC_FUNCTION LC_Token *LC_Match(LC_TokenKind kind); +LC_FUNCTION LC_Token *LC_MatchKeyword(LC_Intern intern); +LC_FUNCTION LC_Precedence LC_GetPrecedence(LC_PrecedenceKind binding, LC_TokenKind kind); +LC_FUNCTION LC_AST *LC_ParseExprEx(int min_bp); +LC_FUNCTION LC_AST *LC_ParseCompo(LC_Token *pos, LC_AST *left); +LC_FUNCTION LC_AST *LC_ParseExpr(void); +LC_FUNCTION LC_AST *LC_ParseProcType(LC_Token *pos); +LC_FUNCTION LC_AST *LC_ParseType(void); +LC_FUNCTION LC_AST *LC_ParseForStmt(LC_Token *pos); +LC_FUNCTION LC_AST *LC_ParseSwitchStmt(LC_Token *pos); +LC_FUNCTION LC_AST *LC_ParseStmt(bool check_semicolon); +LC_FUNCTION LC_AST *LC_ParseStmtBlock(int flags); +LC_FUNCTION LC_AST *LC_ParseProcDecl(LC_Token *name); +LC_FUNCTION LC_AST *LC_ParseStruct(LC_ASTKind kind, LC_Token *ident); +LC_FUNCTION LC_AST *LC_ParseTypedef(LC_Token *ident); +LC_FUNCTION LC_AST *LC_CreateNote(LC_Token *pos, LC_Intern ident); +LC_FUNCTION LC_AST *LC_ParseNote(void); +LC_FUNCTION LC_AST *LC_ParseNotes(void); +LC_FUNCTION bool LC_ResolveBuildIf(LC_AST *build_if); +LC_FUNCTION LC_AST *LC_ParseImport(void); +LC_FUNCTION LC_AST *LC_ParseDecl(LC_AST *file); +LC_FUNCTION bool LC_EatUntilNextValidDecl(void); +LC_FUNCTION bool LC_ParseHashBuildOn(LC_AST *n); +LC_FUNCTION LC_AST *LC_ParseFileEx(LC_AST *package); // // Resolution functions diff --git a/src/compiler/parse.c b/src/compiler/parse.c index ac74cc0..d4da2d4 100644 --- a/src/compiler/parse.c +++ b/src/compiler/parse.c @@ -102,39 +102,35 @@ LC_FUNCTION LC_Token *LC_MatchKeyword(LC_Intern intern) { // Pratt expression parser // Based on this really good article: https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html // clang-format off -LC_FUNCTION LC_BindingPower LC_MakeBP(int left, int right) { - LC_BindingPower result = {left, right}; - return result; -} - -LC_FUNCTION LC_BindingPower LC_GetBindingPower(LC_Binding binding, LC_TokenKind kind) { - if (binding == LC_Binding_Prefix) goto Prefix; - if (binding == LC_Binding_Infix) goto Infix; - if (binding == LC_Binding_Postfix) goto Postfix; +LC_FUNCTION LC_Precedence LC_MakePrecedence(int left, int right) { return {left, right}; } +LC_FUNCTION LC_Precedence LC_GetPrecedence(LC_PrecedenceKind p, LC_TokenKind kind) { + if (p == LC_PrecedenceKind_Prefix) goto Prefix; + if (p == LC_PrecedenceKind_Infix) goto Infix; + if (p == LC_PrecedenceKind_Postfix) goto Postfix; LC_ASSERT(NULL, !"invalid codepath"); Prefix: switch (kind) { - case LC_TokenKind_OpenBracket: return LC_MakeBP(-2, 22); + case LC_TokenKind_OpenBracket: return LC_MakePrecedence(-2, 22); case LC_TokenKind_Mul: case LC_TokenKind_BitAnd: case LC_TokenKind_Keyword: case LC_TokenKind_OpenParen: - case LC_TokenKind_Sub: case LC_TokenKind_Add: case LC_TokenKind_Neg: case LC_TokenKind_Not: case LC_TokenKind_OpenBrace: return LC_MakeBP(-2, 20); - default: return LC_MakeBP(-1, -1); + case LC_TokenKind_Sub: case LC_TokenKind_Add: case LC_TokenKind_Neg: case LC_TokenKind_Not: case LC_TokenKind_OpenBrace: return LC_MakePrecedence(-2, 20); + default: return LC_MakePrecedence(-1, -1); } Infix: switch (kind) { - case LC_TokenKind_Or: return LC_MakeBP(9, 10); - case LC_TokenKind_And: return LC_MakeBP(11, 12); + case LC_TokenKind_Or: return LC_MakePrecedence(9, 10); + case LC_TokenKind_And: return LC_MakePrecedence(11, 12); case LC_TokenKind_Equals: case LC_TokenKind_NotEquals: case LC_TokenKind_GreaterThen: - case LC_TokenKind_GreaterThenEq: case LC_TokenKind_LesserThen: case LC_TokenKind_LesserThenEq: return LC_MakeBP(13, 14); - case LC_TokenKind_Sub: case LC_TokenKind_Add: case LC_TokenKind_BitOr: case LC_TokenKind_BitXor: return LC_MakeBP(15, 16); + case LC_TokenKind_GreaterThenEq: case LC_TokenKind_LesserThen: case LC_TokenKind_LesserThenEq: return LC_MakePrecedence(13, 14); + case LC_TokenKind_Sub: case LC_TokenKind_Add: case LC_TokenKind_BitOr: case LC_TokenKind_BitXor: return LC_MakePrecedence(15, 16); case LC_TokenKind_RightShift: case LC_TokenKind_LeftShift: case LC_TokenKind_BitAnd: - case LC_TokenKind_Mul: case LC_TokenKind_Div: case LC_TokenKind_Mod: return LC_MakeBP(17, 18); - default: return LC_MakeBP(0, 0); + case LC_TokenKind_Mul: case LC_TokenKind_Div: case LC_TokenKind_Mod: return LC_MakePrecedence(17, 18); + default: return LC_MakePrecedence(0, 0); } Postfix: switch (kind) { - case LC_TokenKind_Dot: case LC_TokenKind_OpenBracket: case LC_TokenKind_OpenParen: return LC_MakeBP(21, -2); - default: return LC_MakeBP(-1, -1); + case LC_TokenKind_Dot: case LC_TokenKind_OpenBracket: case LC_TokenKind_OpenParen: return LC_MakePrecedence(21, -2); + default: return LC_MakePrecedence(-1, -1); } } @@ -142,7 +138,7 @@ LC_FUNCTION LC_AST *LC_ParseExprEx(int min_bp) { LC_AST *left = NULL; LC_Token *prev = LC_GetI(-1); LC_Token *t = LC_Next(); - LC_BindingPower prefixbp = LC_GetBindingPower(LC_Binding_Prefix, t->kind); + LC_Precedence prefixbp = LC_GetPrecedence(LC_PrecedenceKind_Prefix, t->kind); // parse prefix expression switch (t->kind) { @@ -240,8 +236,8 @@ LC_FUNCTION LC_AST *LC_ParseExprEx(int min_bp) { // it's not so we don't recurse - we break // We do the for loop instead - LC_BindingPower postfix_bp = LC_GetBindingPower(LC_Binding_Postfix, t->kind); - LC_BindingPower infix_bp = LC_GetBindingPower(LC_Binding_Infix, t->kind); + LC_Precedence postfix_bp = LC_GetPrecedence(LC_PrecedenceKind_Postfix, t->kind); + LC_Precedence infix_bp = LC_GetPrecedence(LC_PrecedenceKind_Infix, t->kind); // parse postfix expression if (postfix_bp.left > min_bp) {