WHY:
ONYX was made to help me learn about compiler design.
+END GOAL:
+ ONYX will be used to make a simple-ish game for the browser that leverages
+ WASM and WebGL for a performant experience. Language design will reflect the
+ needs of the game programming.
+
FEATURES:
- Strong type system
- - Smart package loading
- - Structs and enums
- functions (no anonymous functions)
+ - Structs and enums
- Control structures
if, for, switch
- pointers
- inferred typing
+ - Smart package loading
- defer
? polymorphic functions
use "core"; // Looks for "core.onyx" in the current directory
-Foo :: struct { x: i32, y: i32 };
+Foo :: struct { x i32, y i32 };
-export add :: (a: i32, b: i32) -> i32 {
- return a + b;
+export add :: proc (a i32, b i32) -> i32 {
+ return a + b;
};
-foo :: (a: i32) -> Foo {
+foo :: proc (a i32) -> Foo {
return Foo { x = a, y = 0 };
}
/* Comments need to be parsed */
-export proc add :: (a i32, b i32) -> i32 {
+export add :: proc (a i32, b i32) -> i32 {
return a + b;
}
-export proc max :: (a i32, b i32) -> i32 {
+export max :: proc (a i32, b i32) -> i32 {
/* Curly braces are required */
-
if a > b {
return a;
} else {
return b;
}
-}
\ No newline at end of file
+}
--- /dev/null
+Type checking at parse time:\r
+ Why couldn't this work?\r
+ * Every variable is of known type or the type must be known by immediate assignment\r
+ * This requires that functions are declared in a particular order like C\r
+ * This also requires immediate evaluation of external symbols (C #include style)\r
+ - Don't like this at all\r
+ - Want a proper module system\r
+\r
+ /* foo.onyx */\r
+ foo :: proc (a i32) -> f32 {\r
+ return a as f32;\r
+ }\r
+\r
+\r
+ /* main.onyx */\r
+ use "foo";\r
+\r
+ export main :: proc () -> void {\r
+ a := 2.0f + foo(5);\r
+ }\r
+\r
+ foo(5) would have a left node of SYMBOL:foo\r
+ This will be resolved in a later stage between the parsing and semantic pass\r
+ \r
case TOKEN_TYPE_SYMBOL: {
OnyxToken* sym_token = expect(parser, TOKEN_TYPE_SYMBOL);
OnyxAstNode* sym_node = lookup_identifier(parser, sym_token);
+ if (sym_node == NULL) {
+ onyx_token_null_toggle(*sym_token);
+ onyx_message_add(parser->msgs,
+ ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
+ sym_token->pos, sym_token->token);
+ onyx_token_null_toggle(*sym_token);
+ }
// TODO: Handle calling a function
return sym_node;
void onyx_ast_print(OnyxAstNode* node) {
if (node == NULL) return;
-
- bh_printf("%s <%d> ", onyx_ast_node_kind_string(node->kind), node->flags);
- if (node->token)
- bh_printf("[%b] ", node->token->token, (int) node->token->length);
-
- if ((i64) node->left > 10) { // HACK: but okay
- bh_printf("(");
- onyx_ast_print(node->left);
- bh_printf(") ");
- }
- if ((i64) node->right > 10) { // HACK: but okay
- bh_printf("(");
- onyx_ast_print(node->right);
- bh_printf(")");
- }
-
- if (node->next) {
- bh_printf("{");
- onyx_ast_print(node->next);
- bh_printf("}");
- }
-
}
return a + b;
}
-c :: proc () -> void ---
-
export mul :: proc (a i32, b i32) -> i32 {
+ /* Typechecked */
c: const i32 = a - b;
/* Don't love this syntax, but it's easy to parse so whatever
Inferred type, but constant */
+ /* a and b are both i32, so i32 + i32 is i32 so d is i32 */
d: const = a + b;
return c * d;