bugfixes and completely removed 'proc' keyword
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 17 Nov 2021 21:00:42 +0000 (15:00 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 17 Nov 2021 21:00:42 +0000 (15:00 -0600)
core/container/set.onyx
core/runtime/wasi.onyx
include/lex.h
misc/onyx-mode.el [new file with mode: 0644]
src/astnodes.c
src/lex.c
src/parser.c
src/polymorph.c
tests/complicated_polymorph.onyx

index dc3c253ed0aa19807f405a3f75ad539a721e06ed..c421bff21c4948b550ae5b0f5128a2444a9d1b65 100644 (file)
@@ -8,7 +8,12 @@ package core.set
 }
 use package core.intrinsics.onyx { __zero_value }
 
-Set :: struct (T: type_expr) {
+#local SetValue :: interface (T: type_expr) {
+    hash.to_u32(T);
+    T == T;
+}
+
+Set :: struct (T: type_expr) where SetValue(T) {
     allocator : Allocator;
 
     hashes  : [] i32;
index 18fa2b5eaf5f7c20bc7b63d8ae12af9024b98bbf..9ad50535251d95e96698577726f16fc164d62f62 100644 (file)
@@ -50,3 +50,7 @@ __exit :: (status: i32) do proc_exit(status);
 
     __flush_stdio();
 }
+
+
+__spawn_thread :: (t: i32, func: (data: rawptr) -> void, data: rawptr) -> bool ---
+__kill_thread :: (t: i32) -> i32 ---
index fb9a9493a01706ea84663bfa054699ddc7bdf3b0..f8d5d1c555cc14fb45c527483ca1fa2c1577c422 100644 (file)
@@ -23,7 +23,6 @@ typedef enum TokenType {
     Token_Type_Keyword_Elseif,
     Token_Type_Keyword_Return,
     Token_Type_Keyword_Global,
-    Token_Type_Keyword_Proc,
     Token_Type_Keyword_As,
     Token_Type_Keyword_Cast,
     Token_Type_Keyword_While,
diff --git a/misc/onyx-mode.el b/misc/onyx-mode.el
new file mode 100644 (file)
index 0000000..8dfea24
--- /dev/null
@@ -0,0 +1,222 @@
+;;; lang/onyx/autoload/onyx.el -*- lexical-binding: t; -*-
+
+
+;; onyx-mode.el - very basic onyx mode
+
+(require 'cl)
+(require 'rx)
+(require 'js)
+
+(defconst onyx-mode-syntax-table
+  (let ((table (make-syntax-table)))
+    (modify-syntax-entry ?\" "\"" table)
+    (modify-syntax-entry ?\\ "\\" table)
+
+    ;; additional symbols
+    (modify-syntax-entry ?_ "w" table)
+
+    (modify-syntax-entry ?' "." table)
+    (modify-syntax-entry ?: "." table)
+    (modify-syntax-entry ?+  "." table)
+    (modify-syntax-entry ?-  "." table)
+    (modify-syntax-entry ?%  "." table)
+    (modify-syntax-entry ?&  "." table)
+    (modify-syntax-entry ?|  "." table)
+    (modify-syntax-entry ?^  "." table)
+    (modify-syntax-entry ?!  "." table)
+    (modify-syntax-entry ?$  "/" table)
+    (modify-syntax-entry ?=  "." table)
+    (modify-syntax-entry ?<  "." table)
+    (modify-syntax-entry ?>  "." table)
+    (modify-syntax-entry ??  "." table)
+
+    ;; Modify some syntax entries to allow nested block comments
+    (modify-syntax-entry ?/ ". 124b" table)
+    (modify-syntax-entry ?* ". 23n" table)
+    (modify-syntax-entry ?\n "> b" table)
+    (modify-syntax-entry ?\^m "> b" table)
+
+    table))
+
+(defconst onyx-builtins
+  '("cast" "it" "sizeof" "alignof" "typeof"))
+
+(defconst onyx-keywords
+  '("if" "elseif" "else" "do" "while" "for" "switch" "case" "struct" "enum"
+    "return" "continue" "break" "fallthrough" "defer" "macro" "package"
+    "use" "interface" "where"))
+
+(defconst onyx-constants
+  '("null" "true" "false" "null_str" "null_proc"))
+
+(defconst onyx-typenames
+  '("u64" "u32" "u16" "u8"
+    "i64" "i32" "i16" "i8"
+    "f32" "f64" "str" "cstr" "any" "type_expr"
+    "bool" "void" "rawptr"
+    "i8x16" "i16x8" "i32x4" "i64x2"
+    "f32x4" "f64x2" "v128"))
+
+(defun onyx-wrap-word-rx (s)
+  (concat "\\<" s "\\>"))
+
+(defun onyx-keywords-rx (keywords)
+  "build keyword regexp"
+  (onyx-wrap-word-rx (regexp-opt keywords t)))
+
+(defconst onyx-hat-type-rx (rx (group (and "^" (1+ word)))))
+(defconst onyx-dollar-type-rx (rx (group "$" (or (1+ word) (opt "$")))))
+(defconst onyx-number-rx
+  (rx (and
+       symbol-start
+       (or (and (+ digit) (opt (and (any "eE") (opt (any "-+")) (+ digit))))
+           (and "0" (any "xX") (+ hex-digit)))
+       (opt (and (any "_" "A-Z" "a-z") (* (any "_" "A-Z" "a-z" "0-9"))))
+       symbol-end)))
+
+(defconst onyx-font-lock-defaults
+  `(
+    ;; Keywords
+    (,(onyx-keywords-rx onyx-keywords) 1 font-lock-keyword-face)
+
+    ;; single quote characters
+    ("\\('[[:word:]]\\)\\>" 1 font-lock-constant-face)
+
+    ;; Variables
+    (,(onyx-keywords-rx onyx-builtins) 1 font-lock-variable-name-face)
+
+    ;; Constants
+    (,(onyx-keywords-rx onyx-constants) 1 font-lock-constant-face)
+
+    ;; Hash directives
+    ("#\\w+" . font-lock-preprocessor-face)
+
+    ;; At directives
+    ("@\\w+" . font-lock-preprocessor-face)
+
+    ;; Strings
+    ("\\\".*\\\"" . font-lock-string-face)
+
+    ;; Numbers
+    (,(onyx-wrap-word-rx onyx-number-rx) . font-lock-constant-face)
+
+    ;; Types
+    (,(onyx-keywords-rx onyx-typenames) 1 font-lock-type-face)
+    (,onyx-dollar-type-rx 1 font-lock-type-face)
+
+    ("---" . font-lock-constant-face)
+    ))
+
+;; add setq-local for older emacs versions
+(unless (fboundp 'setq-local)
+  (defmacro setq-local (var val)
+    `(set (make-local-variable ',var) ,val)))
+
+(defconst onyx--defun-rx "\(.*\).*\{")
+
+(defmacro onyx-paren-level ()
+  `(car (syntax-ppss)))
+
+(defun onyx-line-is-defun ()
+  "return t if current line begins a procedure"
+  (interactive)
+  (save-excursion
+    (beginning-of-line)
+    (let (found)
+      (while (and (not (eolp)) (not found))
+        (if (looking-at onyx--defun-rx)
+            (setq found t)
+          (forward-char 1)))
+      found)))
+
+(defun onyx-beginning-of-defun (&optional count)
+  "Go to line on which current function starts."
+  (interactive)
+  (let ((orig-level (onyx-paren-level)))
+    (while (and
+            (not (onyx-line-is-defun))
+            (not (bobp))
+            (> orig-level 0))
+      (setq orig-level (onyx-paren-level))
+      (while (>= (onyx-paren-level) orig-level)
+        (skip-chars-backward "^{")
+        (backward-char))))
+  (if (onyx-line-is-defun)
+      (beginning-of-line)))
+
+(defun onyx-end-of-defun ()
+  "Go to line on which current function ends."
+  (interactive)
+  (let ((orig-level (onyx-paren-level)))
+    (when (> orig-level 0)
+      (onyx-beginning-of-defun)
+      (end-of-line)
+      (setq orig-level (onyx-paren-level))
+      (skip-chars-forward "^}")
+      (while (>= (onyx-paren-level) orig-level)
+        (skip-chars-forward "^}")
+        (forward-char)))))
+
+(defalias 'onyx-parent-mode
+ (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
+
+;; imenu hookup
+(add-hook 'onyx-mode-hook
+      (lambda ()
+        (setq imenu-generic-expression
+          '(
+            ("type" "^\\(.*:*.*\\) : " 1)
+           ("function" "^\\(.*\\) :: " 1)
+           ("struct" "^\\(.*\\) *:: *\\(struct\\)\\(.*\\){" 1)
+           )
+        )
+      )
+)
+
+;; NOTE: taken from the scala-indent package and modified for Onyx.
+;;   Still uses the js-indent-line as a base, which will have to be
+;;   replaced when the language is more mature.
+(defun onyx--indent-on-parentheses ()
+  (when (and (= (char-syntax (char-before)) ?\))
+             (= (save-excursion (back-to-indentation) (point)) (1- (point))))
+    (js-indent-line)))
+
+(defun onyx--add-self-insert-hooks ()
+  (add-hook 'post-self-insert-hook
+            'onyx--indent-on-parentheses)
+  )
+
+(require 'compile)
+(add-hook 'onyx-mode-hook (lambda ()
+        (add-to-list 'compilation-error-regexp-alist 'onyx)
+        (add-to-list 'compilation-error-regexp-alist-alist '(onyx "^(\\(.*\\):\\([0-9]+\\),\\([0-9]+\\)) \\(.*\\)" 1 2 3))
+  ))
+
+;; (add-hook 'onyx-mode-hook (lambda()
+;;        (rainbow-delimiters-mode)
+;; ))
+
+;;;###autoload
+(define-derived-mode onyx-mode onyx-parent-mode "Onyx"
+ :syntax-table onyx-mode-syntax-table
+ :group 'onyx
+ (setq bidi-paragraph-direction 'left-to-right)
+ (setq-local require-final-newline mode-require-final-newline)
+ (setq-local parse-sexp-ignore-comments t)
+ (setq-local comment-start-skip "\\(//+\\|/\\*+\\)\\s *")
+ (setq-local comment-start "/*")
+ (setq-local comment-end "*/")
+ (setq-local indent-line-function 'js-indent-line)
+ (setq-local font-lock-defaults '(onyx-font-lock-defaults))
+ (setq-local beginning-of-defun-function 'onyx-beginning-of-defun)
+ (setq-local end-of-defun-function 'onyx-end-of-defun)
+
+ ;; add indent functionality to some characters
+ (onyx--add-self-insert-hooks)
+
+ (font-lock-fontify-buffer))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.onyx\\'" . onyx-mode))
+
+(provide 'onyx-mode)
index 07307593946cbbbda2d7fb0fcdca36fb06dc7384..50c9a629e0a7dae727a7297074868ac18ae36174 100644 (file)
@@ -573,7 +573,7 @@ TypeMatch unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) {
     if (node->kind == Ast_Kind_Unary_Field_Access) {
         AstType* ast_type = type->ast_type;
         AstNode* resolved = try_symbol_resolve_from_node((AstNode *) ast_type, node->token);
-        if (resolved == NULL) return TYPE_MATCH_FAILED;
+        if (resolved == NULL) return TYPE_MATCH_YIELD;
 
         if (permanent) *pnode = (AstTyped *) resolved;
         return TYPE_MATCH_SUCCESS;
index a19b6759ed8ffe2e31973b7f088cf30d49b777cd..e3152c48e3dc3938b05150b44255fbee00ef8818 100644 (file)
--- a/src/lex.c
+++ b/src/lex.c
@@ -21,7 +21,6 @@ static const char* token_type_names[] = {
     "elseif",
     "return",
     "global",
-    "proc",
     "as",
     "cast",
     "while",
@@ -366,7 +365,6 @@ whitespace_skipped:
         break;
     case 'p':
         LITERAL_TOKEN("package",     1, Token_Type_Keyword_Package);
-        LITERAL_TOKEN("proc",        1, Token_Type_Keyword_Proc);
         break;
     case 'r':
         LITERAL_TOKEN("return",      1, Token_Type_Keyword_Return);
index f7222b68172331fc22e6deec554b8a9d79418465..9c8dde2dc50f9157db5202e3634106add49e19f9 100644 (file)
@@ -1717,14 +1717,6 @@ static AstType* parse_type(OnyxParser* parser) {
                 break;
             }
 
-            case Token_Type_Keyword_Proc: {
-                OnyxToken* proc_token = expect_token(parser, Token_Type_Keyword_Proc);
-                onyx_report_warning(proc_token->pos, "Warning: 'proc' is a deprecated keyword.");
-                *next_insertion = parse_function_type(parser, proc_token);
-                next_insertion = NULL;
-                break;
-            }
-
             case '$': {
                 parse_polymorphic_variable(parser, &next_insertion);
                 break;
@@ -2284,21 +2276,32 @@ static AstFunction* parse_function_definition(OnyxParser* parser, OnyxToken* tok
 
     func_def->return_type = (AstType *) &basic_type_void;
 
+    char* name = NULL;
+    if (bh_arr_length(parser->current_symbol_stack) > 0) {
+        OnyxToken *current_symbol = bh_arr_last(parser->current_symbol_stack);
+        name = bh_aprintf(global_heap_allocator, "%b", current_symbol->text, current_symbol->length);
+    }
+
     if (consume_token_if_next(parser, '=')) {
         expect_token(parser, '>');
         func_def->return_type = (AstType *) &basic_type_auto_return;
 
-        AstTyped* returned_value = parse_compound_expression(parser, 0);
+        if (parser->curr->type == '{') {
+            func_def->body = parse_block(parser, 1, name);
 
-        AstReturn* return_node = make_node(AstReturn, Ast_Kind_Return);
-        return_node->token = returned_value->token;
-        return_node->expr = returned_value;
+        } else {
+            AstTyped* returned_value = parse_compound_expression(parser, 0);
 
-        AstBlock* body_block = make_node(AstBlock, Ast_Kind_Block);
-        body_block->token = returned_value->token;
-        body_block->body = (AstNode *) return_node;
+            AstReturn* return_node = make_node(AstReturn, Ast_Kind_Return);
+            return_node->token = returned_value->token;
+            return_node->expr = returned_value;
 
-        func_def->body = body_block;
+            AstBlock* body_block = make_node(AstBlock, Ast_Kind_Block);
+            body_block->token = returned_value->token;
+            body_block->body = (AstNode *) return_node;
+
+            func_def->body = body_block;
+        }
 
         goto function_defined;
     }
@@ -2344,11 +2347,6 @@ static AstFunction* parse_function_definition(OnyxParser* parser, OnyxToken* tok
         }
     }
 
-    char* name = NULL;
-    if (bh_arr_length(parser->current_symbol_stack) > 0) {
-        OnyxToken *current_symbol = bh_arr_last(parser->current_symbol_stack);
-        name = bh_aprintf(global_heap_allocator, "%b", current_symbol->text, current_symbol->length);
-    }
     func_def->body = parse_block(parser, 1, name);
 
 function_defined:
index cfa25705b67b909e3704ad3218e3263df5754a59..8c5d237faeeb8d0fb0f6281d350c87f969226525 100644 (file)
@@ -419,6 +419,11 @@ static AstTyped* try_lookup_based_on_partial_function_type(AstPolyProc *pp, AstF
         AstType *old_return_type = ft->return_type;
         ft->return_type = (AstType *) &basic_type_void;
         ft->partial_function_type = type_build_from_ast(context.ast_alloc, (AstType *) ft);
+        if (!ft->partial_function_type) {
+            doing_nested_polymorph_lookup = 1;
+            return NULL;
+        }
+
         assert(ft->partial_function_type);
         ft->return_type = old_return_type;
     }
index 9b7c468c8d1e0a7e909135db88eb258e9c42d705..41b457591d643d79e08b28cc324c7b17d7c247c2 100644 (file)
@@ -36,4 +36,43 @@ main :: (args: [] cstr) {
       |> convert(f32)
       |> map((x) => x * 4 + 2)
       |> println();
+
+
+    // This does not work at the moment
+    #if false {
+        Color :: enum {
+            Red; Orange; Yellow; Blue;
+        }
+
+        Guy :: struct {
+            best_friend: ^Guy;
+            favorite_color: Color;
+        }
+
+        nightmare :: (x: (typeof(z.best_friend), $K) -> void,
+                      y: (typeof(x)) -> $R,
+                      z: ^$SomeType,
+                      w: R) {
+            k := y(x);
+        }
+
+        dummy1 :: (a: $T, b: typeof(a.favorite_color)) -> void {
+            printf("dummy1 got T={}, typeof(a.favorite_color)={}\n", a, typeof(b));
+        }
+
+        dummy2 :: (f: (a: ^Guy, b: $C) -> void) -> C {
+            printf("dummy2 got C={}\n", C);
+
+            other_guy := new(Guy);
+            f(other_guy, .Orange);
+
+            default: C;
+            return default;
+        }
+
+        guy := new(Guy);
+        guy.best_friend = guy;
+
+        nightmare(dummy1, dummy2, guy, .Orange);
+    }
 }