OBJ_FILES=\
- build/onyxlex.o \
- build/onyxparser.o \
+ build/onyxlex.o \
+ build/onyxparser.o \
build/onyxtypes.o \
- build/onyxsempass.o \
- build/onyxsymres.o \
- build/onyxchecker.o \
- build/onyxmsgs.o \
- build/onyxutils.o \
- build/onyxwasm.o \
- build/onyx.o
+ build/onyxsempass.o \
+ build/onyxsymres.o \
+ build/onyxchecker.o \
+ build/onyxmsgs.o \
+ build/onyxutils.o \
+ build/onyxwasm.o \
+ build/onyx.o
CC=gcc
INCLUDES=-I./include
install: $(TARGET)
cp $(TARGET) /usr/bin/
+install_syntax: misc/onyx.vim misc/onyx.sublime-syntax
+ cp ./misc/onyx.vim /usr/share/vim/vim82/syntax/onyx.vim
+ cp ./misc/onyx.sublime-syntax /home/brendan/.config/sublime-text-3/Packages/User/onyx.sublime-syntax
+
clean:
rm -f $(OBJ_FILES) 2>&1 >/dev/null
typedef struct AstStructMember AstStructMember;
typedef struct AstBinding AstBinding;
-typedef struct AstUse AstUse;
+typedef struct AstIncludeFile AstIncludeFile;
+typedef struct AstUsePackage AstUsePackage;
typedef struct AstGlobal AstGlobal;
typedef struct AstFunction AstFunction;
typedef struct AstOverloadedFunction AstOverloadedFunction;
+typedef struct AstPackage AstPackage;
+typedef struct Package Package;
typedef struct Scope {
struct Scope *parent;
typedef enum AstKind {
Ast_Kind_Error,
Ast_Kind_Program,
- Ast_Kind_Use,
+ Ast_Kind_Package,
+ Ast_Kind_Include_File,
+ Ast_Kind_Use_Package,
Ast_Kind_Binding,
Ast_Kind_Function,
// Top level nodes
struct AstBinding { AstTyped_base; AstNode* node; };
-struct AstForeign { AstNode_base; OnyxToken *mod_token, *name_token; AstNode *import; };
-struct AstUse { AstNode_base; OnyxToken *filename; };
+struct AstForeign { AstNode_base; OnyxToken *mod_token, *name_token; AstNode *import; };
+struct AstIncludeFile { AstNode_base; OnyxToken *filename; };
+struct AstUsePackage {
+ AstNode_base;
+
+ AstPackage *package;
+ OnyxToken *alias;
+ bh_arr(OnyxToken *) only;
+};
struct AstGlobal {
AstTyped_base;
bh_arr(AstTyped *) overloads;
};
+struct AstPackage {
+ AstNode_base;
+
+ Package* package;
+};
// NOTE: An Entity represents something will need to be
// processed later down the pipeline.
typedef enum EntityType {
Entity_Type_Unknown,
+ Entity_Type_Use_Package,
Entity_Type_String_Literal,
Entity_Type_Struct,
Entity_Type_Function_Header,
typedef struct Entity {
EntityType type;
+ Scope *scope;
union {
+ AstUsePackage *use_package;
AstFunction *function;
AstOverloadedFunction *overloaded_function;
AstGlobal *global;
};
} Entity;
+struct Package {
+ char *name;
+ Scope *scope;
+};
// NOTE: Simple data structure for storing what comes out of the parser
typedef struct ProgramInfo {
- bh_arr(AstBinding *) bindings;
+ Scope *global_scope;
+
+ bh_table(Package *) packages;
bh_arr(Entity) entities;
u32 foreign_func_count;
Token_Type_Comment = 258,
- Token_Type_Keyword_Struct = 259,
- Token_Type_Keyword_Enum = 260,
- Token_Type_Keyword_Use = 261,
- Token_Type_Keyword_Export = 262,
- Token_Type_Keyword_If = 263,
- Token_Type_Keyword_Else = 264,
- Token_Type_Keyword_Elseif = 265,
- Token_Type_Keyword_Return = 266,
- Token_Type_Keyword_Global = 267,
- Token_Type_Keyword_Proc = 268,
- Token_Type_Keyword_Cast = 269,
- Token_Type_Keyword_While = 270,
- Token_Type_Keyword_For = 271,
- Token_Type_Keyword_Break = 272,
- Token_Type_Keyword_Continue = 273,
- Token_Type_Keyword_Sizeof = 274,
-
- Token_Type_Right_Arrow = 275,
- Token_Type_Left_Arrow = 276,
- Token_Type_Empty_Block = 277,
-
- Token_Type_Greater_Equal = 278,
- Token_Type_Less_Equal = 279,
- Token_Type_Equal_Equal = 280,
- Token_Type_Not_Equal = 281,
- Token_Type_Plus_Equal = 282,
- Token_Type_Minus_Equal = 283,
- Token_Type_Star_Equal = 284,
- Token_Type_Fslash_Equal = 285,
- Token_Type_Percent_Equal = 286,
- Token_Type_And_Equal = 287,
- Token_Type_Or_Equal = 288,
- Token_Type_Xor_Equal = 289,
- Token_Type_And_And = 290,
- Token_Type_Or_Or = 291,
- Token_Type_Shift_Left = 292,
- Token_Type_Shift_Right = 293,
- Token_Type_Shift_Arith_Right = 294,
- Token_Type_Shl_Equal = 295,
- Token_Type_Shr_Equal = 296,
- Token_Type_Sar_Equal = 297,
-
- Token_Type_Symbol = 298,
- Token_Type_Literal_String = 299,
- Token_Type_Literal_Numeric = 300,
- Token_Type_Literal_True = 301,
- Token_Type_Literal_False = 302,
-
- Token_Type_Count = 303,
+ Token_Type_Keyword_Package,
+ Token_Type_Keyword_Struct,
+ Token_Type_Keyword_Enum,
+ Token_Type_Keyword_Use,
+ Token_Type_Keyword_If,
+ Token_Type_Keyword_Else,
+ Token_Type_Keyword_Elseif,
+ Token_Type_Keyword_Return,
+ Token_Type_Keyword_Global,
+ Token_Type_Keyword_Proc,
+ Token_Type_Keyword_Cast,
+ Token_Type_Keyword_While,
+ Token_Type_Keyword_For,
+ Token_Type_Keyword_Break,
+ Token_Type_Keyword_Continue,
+ Token_Type_Keyword_Sizeof,
+
+ Token_Type_Right_Arrow,
+ Token_Type_Left_Arrow,
+ Token_Type_Empty_Block,
+
+ Token_Type_Greater_Equal,
+ Token_Type_Less_Equal,
+ Token_Type_Equal_Equal,
+ Token_Type_Not_Equal,
+ Token_Type_Plus_Equal,
+ Token_Type_Minus_Equal,
+ Token_Type_Star_Equal,
+ Token_Type_Fslash_Equal,
+ Token_Type_Percent_Equal,
+ Token_Type_And_Equal,
+ Token_Type_Or_Equal,
+ Token_Type_Xor_Equal,
+ Token_Type_And_And,
+ Token_Type_Or_Or,
+ Token_Type_Shift_Left,
+ Token_Type_Shift_Right,
+ Token_Type_Shift_Arith_Right,
+ Token_Type_Shl_Equal,
+ Token_Type_Shr_Equal,
+ Token_Type_Sar_Equal,
+
+ Token_Type_Symbol,
+ Token_Type_Literal_String,
+ Token_Type_Literal_Numeric,
+ Token_Type_Literal_True,
+ Token_Type_Literal_False,
+
+ Token_Type_Count,
} TokenType;
typedef struct OnyxFilePos {
#include "onyxmsgs.h"
#include "onyxastnodes.h"
+typedef struct NodeToProcess {
+ Scope *scope;
+ AstNode *node;
+} NodeToProcess;
+
typedef struct ParseResults {
// NOTE: The allocator used to make the arrays below
bh_allocator allocator;
- bh_arr(AstUse *) uses;
- bh_arr(AstBinding *) bindings;
+ bh_arr(AstIncludeFile *) files;
// NOTE: Contains all the nodes that will need some processing (symbol resolution, type checking)
- bh_arr(AstNode *) nodes_to_process;
+ bh_arr(NodeToProcess) nodes_to_process;
} ParseResults;
typedef struct OnyxParser {
bh_allocator allocator;
+ ProgramInfo *program;
+ Scope *package_scope;
+
// NOTE: not used since all tokens are lexed before parsing starts
OnyxTokenizer *tokenizer;
OnyxToken *prev;
const char* onyx_ast_node_kind_string(AstKind kind);
void* onyx_ast_node_new(bh_allocator alloc, i32 size, AstKind kind);
-OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer);
+OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, ProgramInfo *program);
void onyx_parser_free(OnyxParser* parser);
ParseResults onyx_parse(OnyxParser *parser);
const char* onyx_ast_node_kind_string(AstKind kind);
+void program_info_init(ProgramInfo* prog, bh_allocator alloc);
+Package* program_info_package_lookup(ProgramInfo* prog, char* package_name);
+Package* program_info_package_lookup_or_create(ProgramInfo* prog, char* package_name, Scope* parent_scope, bh_allocator alloc);
+
+Scope* scope_create(bh_allocator a, Scope* parent);
+void scope_include(Scope* target, Scope* source);
+b32 symbol_introduce(Scope* scope, OnyxToken* tkn, AstNode* symbol);
+b32 symbol_raw_introduce(Scope* scope, char* tkn, OnyxFilePos pos, AstNode* symbol);
+void symbol_builtin_introduce(Scope* scope, char* sym, AstNode *node);
+AstNode* symbol_resolve(Scope* start_scope, OnyxToken* tkn);
+
void onyx_ast_print(AstNode* program, i32 indent);
# strings in YAML. When using single quoted strings, only single quotes
# need to be escaped: this is done by using two single quotes next to each
# other.
- - match: '\b(struct|proc|use|global|enum|if|elseif|else|for|while|do|break|continue|return|as|sizeof)\b'
+ - match: '\b(package|struct|proc|use|global|enum|if|elseif|else|for|while|do|break|continue|return|as|sizeof)\b'
scope: keyword.control.onyx
- - match: '\b(unknown|bool|void|i8|u8|i16|u16|i32|u32|i64|u64|f32|f64|rawptr)\b'
+ - match: '\b(bool|void|i8|u8|i16|u16|i32|u32|i64|u64|f32|f64|rawptr)\b'
scope: constant.type.onyx
- match: '\b(true|false)\b'
let s:cpo_save = &cpo
set cpo&vim
-syn keyword onyxKeyword struct proc use global
+syn keyword onyxKeyword package struct proc use global
syn keyword onyxKeyword if elseif else
syn keyword onyxKeyword for while do
syn keyword onyxKeyword break continue return
syn keyword onyxKeyword as sizeof
-syn keyword onyxType unknown bool void
+syn keyword onyxType bool void
syn keyword onyxType i8 u8
syn keyword onyxType i16 u16
syn keyword onyxType i32 u32
use "progs/intrinsics"
use "progs/print_funcs"
+use package printing
+
global_arr :: global []i32;
min_i32 :: proc (a: i32, b: i32) -> i32 {
-
alloc :: proc (size: u32) -> rawptr {
heap_u32 :: __heap_start as ^u32;
--- /dev/null
+use "progs/print_funcs"
+
+use package printing
+
+Foo :: struct {
+ x : i32;
+ y : i32;
+}
+
+foo_sum :: proc (foo: ^Foo) -> i32 {
+ return foo.x + foo.y;
+}
+
+proc #export "main" {
+ foo := __heap_start as ^Foo;
+ foo.x = 123;
+ foo.y = 321;
+ print(foo.foo_sum());
+
+
+ print(1234);
+
+ print_f32(123.0f);
+}
\ No newline at end of file
+++ /dev/null
-use "progs/test"
-
-other_value :: proc (n: i32) -> i32 {
- return 8675309 + something_else(n) + global_value;
-}
-
-fib :: proc #export (n: i32) -> i32 {
- if n == 0 { return 1; }
- if n == 1 { return 1; }
-
- a := 0;
- b := 1;
-
- count := n;
-
- while count >= 0 {
- count -= 1;
-
- c :: a + b;
- b = a;
- a = c;
- }
-
- return a;
-}
-
-factorial :: proc #export (n: i32) -> i32 {
- if n <= 1 { return 1; }
-
- f := 1;
- i := 2;
-
- while i <= n {
- f *= i;
- i += 1;
- }
-
- return f;
-}
+package printing
+
print_bool :: proc #foreign "host" "print" (value: bool) ---
print_i32 :: proc #foreign "host" "print" (value: i32) ---
print_f32 :: proc #foreign "host" "print" (value: f32) ---
use "progs/print_funcs"
use "progs/intrinsics"
+use package printing
+
N :: 5
Foo :: struct {
use "progs/intrinsics"
use "progs/print_funcs"
+use package printing as printing
+
alloc :: proc (size: u32) -> rawptr {
heap_u32 :: __heap_start as ^u32;
vec.x = 5.0f;
vec.y = 12.0f;
- print(vec.x);
- print(vec.y);
+ printing.print(vec.x);
+ printing.print(vec.y);
mag :: vec.magnitude();
- print(mag);
+ printing.print(mag);
- print((*vec).dot(1.0f, 1.0f));
- print(dot(2.0f, 4.0f, -6.0f, 3.0f));
+ printing.print((*vec).dot(1.0f, 1.0f));
+ printing.print(dot(2.0f, 4.0f, -6.0f, 3.0f));
v3 := alloc(sizeof Vec3) as ^Vec3;
v3.y = 12.0f;
v3.z = 13.0f;
- print(v3.magnitude());
+ printing.print(v3.magnitude());
foo := 5;
foo <<= 2;
foo &= 6;
foo |= 5;
foo >>= 1;
- print(foo);
+ printing.print(foo);
}
\ No newline at end of file
static void compiler_state_init(CompilerState* compiler_state, OnyxCompileOptions* opts) {
compiler_state->options = opts;
- bh_arr_new(global_heap_allocator, compiler_state->prog_info.bindings, 4);
- bh_arr_new(global_heap_allocator, compiler_state->prog_info.entities, 4);
+ program_info_init(&compiler_state->prog_info, global_heap_allocator);
bh_arena_init(&compiler_state->msg_arena, opts->allocator, 4096);
compiler_state->msg_alloc = bh_arena_allocator(&compiler_state->msg_arena);
if (compiler_state->options->verbose_output)
bh_printf("[Parsing] %s\n", file_contents->filename);
- OnyxParser parser = onyx_parser_create(compiler_state->ast_alloc, &tokenizer);
+ OnyxParser parser = onyx_parser_create(compiler_state->ast_alloc, &tokenizer, &compiler_state->prog_info);
return onyx_parse(&parser);
}
}
static void merge_parse_results(CompilerState* compiler_state, ParseResults* results) {
- bh_arr_each(AstUse *, use_node, results->uses) {
+ bh_arr_each(AstIncludeFile *, include, results->files) {
char* formatted_name = bh_aprintf(
global_heap_allocator,
"%b.onyx",
- (*use_node)->filename->text, (*use_node)->filename->length);
+ (*include)->filename->text, (*include)->filename->length);
bh_arr_push(compiler_state->queued_files, formatted_name);
}
- bh_arr_each(AstBinding *, binding_node, results->bindings)
- bh_arr_push(compiler_state->prog_info.bindings, *binding_node);
-
Entity ent;
- bh_arr_each(AstNode *, node, results->nodes_to_process) {
- AstKind nkind = (*node)->kind;
+ bh_arr_each(NodeToProcess, n, results->nodes_to_process) {
+ AstNode* node = n->node;
+ AstKind nkind = node->kind;
+
+ ent.scope = n->scope;
+
switch (nkind) {
case Ast_Kind_Function: {
ent.type = Entity_Type_Function_Header;
- ent.function = (AstFunction *) *node;
+ ent.function = (AstFunction *) node;
bh_arr_push(compiler_state->prog_info.entities, ent);
ent.type = Entity_Type_Function;
- ent.function = (AstFunction *) *node;
+ ent.function = (AstFunction *) node;
bh_arr_push(compiler_state->prog_info.entities, ent);
break;
}
case Ast_Kind_Overloaded_Function: {
ent.type = Entity_Type_Overloaded_Function;
- ent.overloaded_function = (AstOverloadedFunction *) *node;
+ ent.overloaded_function = (AstOverloadedFunction *) node;
bh_arr_push(compiler_state->prog_info.entities, ent);
break;
}
case Ast_Kind_Global: {
ent.type = Entity_Type_Global_Header;
- ent.global = (AstGlobal *) *node;
+ ent.global = (AstGlobal *) node;
bh_arr_push(compiler_state->prog_info.entities, ent);
ent.type = Entity_Type_Global;
- ent.global = (AstGlobal *) *node;
+ ent.global = (AstGlobal *) node;
bh_arr_push(compiler_state->prog_info.entities, ent);
break;
}
case Ast_Kind_StrLit: {
ent.type = Entity_Type_String_Literal;
- ent.strlit = (AstStrLit *) *node;
+ ent.strlit = (AstStrLit *) node;
bh_arr_push(compiler_state->prog_info.entities, ent);
break;
}
case Ast_Kind_Struct_Type: {
ent.type = Entity_Type_Struct;
- ent.struct_type = (AstStructType *) *node;
+ ent.struct_type = (AstStructType *) node;
+ bh_arr_push(compiler_state->prog_info.entities, ent);
+ break;
+ }
+
+ case Ast_Kind_Use_Package: {
+ ent.type = Entity_Type_Use_Package;
+ ent.use_package = (AstUsePackage *) node;
bh_arr_push(compiler_state->prog_info.entities, ent);
break;
}
default: {
ent.type = Entity_Type_Expression;
- ent.expr = (AstTyped *) *node;
+ ent.expr = (AstTyped *) node;
bh_arr_push(compiler_state->prog_info.entities, ent);
break;
}
bh_arr_each(Entity, entity, semstate.program->entities) {
switch (entity->type) {
case Entity_Type_Function_Header:
- if (entity->function->flags & Ast_Kind_Foreign)
+ if (entity->function->flags & Ast_Flag_Foreign)
semstate.program->foreign_func_count++;
if (check_function_header(entity->function)) return;
break;
case Entity_Type_Global:
- if (entity->global->flags & Ast_Kind_Foreign)
+ if (entity->global->flags & Ast_Flag_Foreign)
semstate.program->foreign_global_count++;
if (check_global(entity->global)) return;
case Entity_Type_Global_Header: break;
+ case Entity_Type_Use_Package: break;
+
default: DEBUG_HERE; break;
}
}
"TOKEN_TYPE_COMMENT",
+ "package",
"struct",
+ "enum",
"use",
- "export",
"if",
"else",
"elseif",
"^=",
"&&",
"||",
- "^^",
"<<",
">>",
">>>",
"<<=",
">>=",
- ">>>="
+ ">>>=",
"TOKEN_TYPE_SYMBOL",
"TOKEN_TYPE_LITERAL_STRING",
goto token_parsed;
}
+ LITERAL_TOKEN("package", 1, Token_Type_Keyword_Package);
LITERAL_TOKEN("struct", 1, Token_Type_Keyword_Struct);
LITERAL_TOKEN("enum" , 1, Token_Type_Keyword_Enum);
LITERAL_TOKEN("use", 1, Token_Type_Keyword_Use);
return token;
}
+static void add_node_to_process(OnyxParser* parser, AstNode* node) {
+ bh_arr_push(parser->results.nodes_to_process, ((NodeToProcess) {
+ .scope = parser->package_scope,
+ .node = node,
+ }));
+}
+
+
+
static AstNumLit* parse_numeric_literal(OnyxParser* parser) {
AstNumLit* lit_node = make_node(AstNumLit, Ast_Kind_NumLit);
lit_node->token = expect_token(parser, Token_Type_Literal_Numeric);
str_node->type_node = (AstType *) str_type;
str_node->addr = 0;
- bh_arr_push(parser->results.nodes_to_process, (AstNode *) str_node);
+ add_node_to_process(parser, (AstNode *) str_node);
retval = (AstTyped *) str_node;
break;
global_node->type_node = parse_type(parser);
- bh_arr_push(parser->results.nodes_to_process, (AstNode *) global_node);
+ add_node_to_process(parser, (AstNode *) global_node);
return (AstTyped *) global_node;
}
if (parser->curr->type == Token_Type_Keyword_Proc) {
AstFunction* func_node = parse_function_definition(parser);
- bh_arr_push(parser->results.nodes_to_process, (AstNode *) func_node);
+ add_node_to_process(parser, (AstNode *) func_node);
return (AstTyped *) func_node;
}
static AstNode* parse_top_level_statement(OnyxParser* parser) {
switch (parser->curr->type) {
case Token_Type_Keyword_Use: {
- AstUse* use_node = make_node(AstUse, Ast_Kind_Use);
- use_node->token = expect_token(parser, Token_Type_Keyword_Use);
- use_node->filename = expect_token(parser, Token_Type_Literal_String);
+ OnyxToken* use_token = expect_token(parser, Token_Type_Keyword_Use);
+
+ if (parser->curr->type == Token_Type_Keyword_Package) {
+ consume_token(parser);
+
+ AstUsePackage* upack = make_node(AstUsePackage, Ast_Kind_Use_Package);
+ upack->token = use_token;
+
+ AstNode* pack_symbol = make_node(AstNode, Ast_Kind_Symbol);
+ pack_symbol->token = expect_token(parser, Token_Type_Symbol);
+ upack->package = (AstPackage *) pack_symbol;
+
+ // followed by 'as'
+ if (parser->curr->type == Token_Type_Keyword_Cast) {
+ consume_token(parser);
+ upack->alias = expect_token(parser, Token_Type_Symbol);
+ }
+
+ if (parser->curr->type == '{') {
+ consume_token(parser);
+
+ bh_arr_new(global_heap_allocator, upack->only, 4);
+
+ while (parser->curr->type != '}') {
+ OnyxToken* only_token = expect_token(parser, Token_Type_Symbol);
+
+ bh_arr_push(upack->only, only_token);
+
+ if (parser->curr->type != '}')
+ expect_token(parser, ',');
+ }
- return (AstNode *) use_node;
+ consume_token(parser);
+ }
+
+ add_node_to_process(parser, (AstNode *) upack);
+ return NULL;
+
+ } else {
+ AstIncludeFile* include = make_node(AstIncludeFile, Ast_Kind_Include_File);
+ include->token = use_token;
+ include->filename = expect_token(parser, Token_Type_Literal_String);
+
+ return (AstNode *) include;
+ }
}
case Token_Type_Keyword_Proc:
}
// HACK
- bh_arr_push(parser->results.nodes_to_process, (AstNode *) node);
+ add_node_to_process(parser, (AstNode *) node);
}
AstBinding* binding = make_node(AstBinding, Ast_Kind_Binding);
return node;
}
-OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer) {
+OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, ProgramInfo* program) {
OnyxParser parser;
parser.allocator = alloc;
parser.tokenizer = tokenizer;
parser.curr = tokenizer->tokens;
parser.prev = NULL;
+ parser.program = program;
parser.results = (ParseResults) {
.allocator = global_heap_allocator,
- .uses = NULL,
- .bindings = NULL,
+ .files = NULL,
.nodes_to_process = NULL,
};
- bh_arr_new(parser.results.allocator, parser.results.uses, 4);
- bh_arr_new(parser.results.allocator, parser.results.bindings, 4);
+ bh_arr_new(parser.results.allocator, parser.results.files, 4);
bh_arr_new(parser.results.allocator, parser.results.nodes_to_process, 4);
return parser;
}
ParseResults onyx_parse(OnyxParser *parser) {
+ if (parser->curr->type == Token_Type_Keyword_Package) {
+ consume_token(parser);
+
+ OnyxToken* symbol = expect_token(parser, Token_Type_Symbol);
+
+ token_toggle_end(symbol);
+ Package *package = program_info_package_lookup_or_create(
+ parser->program,
+ symbol->text,
+ parser->program->global_scope,
+ parser->allocator);
+ token_toggle_end(symbol);
+
+ parser->package_scope = package->scope;
+
+ } else {
+ Package *package = program_info_package_lookup_or_create(
+ parser->program,
+ "main",
+ parser->program->global_scope,
+ parser->allocator);
+
+ parser->package_scope = package->scope;
+ }
+
while (parser->curr->type != Token_Type_End_Stream) {
AstNode* curr_stmt = parse_top_level_statement(parser);
while (curr_stmt != NULL) {
switch (curr_stmt->kind) {
- case Ast_Kind_Use: bh_arr_push(parser->results.uses, (AstUse *) curr_stmt); break;
- case Ast_Kind_Binding: bh_arr_push(parser->results.bindings, (AstBinding *) curr_stmt); break;
+ case Ast_Kind_Include_File: bh_arr_push(parser->results.files, (AstIncludeFile *) curr_stmt); break;
+ case Ast_Kind_Binding: {
+ symbol_introduce(parser->package_scope,
+ ((AstBinding *) curr_stmt)->token,
+ ((AstBinding *) curr_stmt)->node);
+ break;
+ }
+
default: assert(("Invalid top level node", 0));
}
#define BH_DEBUG
#include "onyxsempass.h"
#include "onyxparser.h"
+#include "onyxutils.h"
AstBasicType basic_type_void = { { Ast_Kind_Basic_Type, 0, NULL, "void" }, &basic_types[Basic_Kind_Void] };
AstBasicType basic_type_bool = { { Ast_Kind_Basic_Type, 0, NULL, "bool" }, &basic_types[Basic_Kind_Bool] };
{ NULL, NULL },
};
-static b32 symbol_introduce(OnyxToken* tkn, AstNode* symbol);
-static void symbol_builtin_introduce(char* sym, AstNode *node);
-static AstNode* symbol_resolve(OnyxToken* tkn);
static void scope_enter(Scope* new_scope);
static void scope_leave();
static void symres_local(AstLocal** local);
static void symres_call(AstCall* call);
static void symres_size_of(AstSizeOf* so);
+static void symres_field_access(AstFieldAccess** fa);
static void symres_expression(AstTyped** expr);
static void symres_return(AstReturn* ret);
static void symres_if(AstIf* ifnode);
static void symres_function(AstFunction* func);
static void symres_global(AstGlobal* global);
static void symres_overloaded_function(AstOverloadedFunction* ofunc);
-
-static b32 symbol_introduce(OnyxToken* tkn, AstNode* symbol) {
- token_toggle_end(tkn);
-
- if (bh_table_has(AstNode *, semstate.curr_scope->symbols, tkn->text)) {
- onyx_message_add(Msg_Type_Redeclare_Symbol,
- tkn->pos,
- tkn->text);
- token_toggle_end(tkn);
- return 0;
- }
-
- bh_table_put(AstNode *, semstate.curr_scope->symbols, tkn->text, symbol);
-
- if (symbol->kind == Ast_Kind_Local)
- bh_arr_push(semstate.curr_function->locals, (AstLocal *) symbol);
-
- token_toggle_end(tkn);
- return 1;
-}
-
-static void symbol_builtin_introduce(char* sym, AstNode *node) {
- bh_table_put(AstNode *, semstate.curr_scope->symbols, sym, node);
-}
-
-static AstNode* symbol_resolve(OnyxToken* tkn) {
- token_toggle_end(tkn);
-
- AstNode* res = NULL;
- Scope* scope = semstate.curr_scope;
-
- while (res == NULL && scope != NULL) {
- if (bh_table_has(AstNode *, scope->symbols, tkn->text)) {
- res = bh_table_get(AstNode *, scope->symbols, tkn->text);
- } else {
- scope = scope->parent;
- }
- }
-
- if (res == NULL ) {
- onyx_message_add(Msg_Type_Unknown_Symbol,
- tkn->pos,
- tkn->text);
-
- token_toggle_end(tkn);
- return NULL;
- }
-
- if (res->kind == Ast_Kind_Symbol) {
- token_toggle_end(tkn);
- return symbol_resolve(res->token);
- }
-
- token_toggle_end(tkn);
- return res;
-}
+static void symres_use_package(AstUsePackage* package);
static void scope_enter(Scope* new_scope) {
new_scope->parent = semstate.curr_scope;
if (type == NULL) return NULL;
if (type->kind == Ast_Kind_Symbol) {
- return (AstType *) symbol_resolve(((AstNode *) type)->token);
+ return (AstType *) symbol_resolve(semstate.curr_scope, ((AstNode *) type)->token);
}
// NOTE: Already resolved
static void symres_local(AstLocal** local) {
(*local)->type_node = symres_type((*local)->type_node);
- symbol_introduce((*local)->token, (AstNode *) *local);
+ bh_arr_push(semstate.curr_function->locals, *local);
+
+ symbol_introduce(semstate.curr_scope, (*local)->token, (AstNode *) *local);
}
static void symres_call(AstCall* call) {
+ symres_expression((AstTyped **) &call->callee);
+ if (call->callee == NULL) return;
+
if (call->callee->kind == Ast_Kind_Field_Access) {
AstFieldAccess* fa = (AstFieldAccess *) call->callee;
-
- AstTyped* symbol = onyx_ast_node_new(semstate.node_allocator, sizeof(AstTyped), Ast_Kind_Symbol);
- symbol->token = fa->token;
+ if (fa->expr == NULL) return;
AstArgument* implicit_arg = onyx_ast_node_new(semstate.node_allocator, sizeof(AstArgument), Ast_Kind_Argument);
implicit_arg->value = fa->expr;
implicit_arg->token = fa->expr->token;
implicit_arg->next = (AstNode *) call->arguments;
- call->callee = (AstNode *) symbol;
+ call->callee = symbol_resolve(semstate.curr_scope, fa->token);
call->arguments = implicit_arg;
call->arg_count++;
}
- AstNode* callee = symbol_resolve(call->callee->token);
- if (callee)
- call->callee = callee;
- else {
- token_toggle_end(call->callee->token);
- onyx_message_add(Msg_Type_Unknown_Symbol,
- call->callee->token->pos,
- call->callee->token->text);
- token_toggle_end(call->callee->token);
- return;
- }
-
symres_statement_chain((AstNode *) call->arguments, (AstNode **) &call->arguments);
}
so->so_type = symres_type(so->so_type);
}
+static void symres_field_access(AstFieldAccess** fa) {
+ symres_expression(&(*fa)->expr);
+ if ((*fa)->expr == NULL) return;
+
+ if ((*fa)->expr->kind == Ast_Kind_Package) {
+ AstPackage* package = (AstPackage *) (*fa)->expr;
+ AstNode* n = symbol_resolve(package->package->scope, (*fa)->token);
+ if (n) {
+ // NOTE: not field access
+ *fa = (AstFieldAccess *) n;
+ }
+ }
+}
+
static void symres_unaryop(AstUnaryOp** unaryop) {
if ((*unaryop)->operation == Unary_Op_Cast) {
(*unaryop)->type_node = symres_type((*unaryop)->type_node);
case Ast_Kind_Block: symres_block((AstBlock *) *expr); break;
case Ast_Kind_Symbol:
- *expr = (AstTyped *) symbol_resolve(((AstNode *) *expr)->token);
+ *expr = (AstTyped *) symbol_resolve(semstate.curr_scope, ((AstNode *) *expr)->token);
break;
// NOTE: This is a good case, since it means the symbol is already resolved
case Ast_Kind_Address_Of: symres_expression(&((AstAddressOf *)(*expr))->expr); break;
case Ast_Kind_Dereference: symres_expression(&((AstDereference *)(*expr))->expr); break;
- case Ast_Kind_Field_Access: symres_expression(&((AstFieldAccess *)(*expr))->expr); break;
+ case Ast_Kind_Field_Access: symres_field_access((AstFieldAccess **) expr); break;
case Ast_Kind_Size_Of: symres_size_of((AstSizeOf *)*expr); break;
case Ast_Kind_Array_Access:
fornode->scope = scope_create(semstate.node_allocator, semstate.curr_scope);
scope_enter(fornode->scope);
- symbol_introduce(fornode->var->token, (AstNode *) fornode->var);
+ bh_arr_push(semstate.curr_function->locals, fornode->var);
+ symbol_introduce(semstate.curr_scope, fornode->var->token, (AstNode *) fornode->var);
symres_expression(&fornode->start);
symres_expression(&fornode->end);
for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->next) {
param->type_node = symres_type(param->type_node);
- symbol_introduce(param->token, (AstNode *) param);
+ symbol_introduce(semstate.curr_scope, param->token, (AstNode *) param);
}
if (func->type_node != NULL) {
static void symres_overloaded_function(AstOverloadedFunction* ofunc) {
bh_arr_each(AstTyped *, node, ofunc->overloads) {
if ((*node)->kind == Ast_Kind_Symbol) {
- *node = (AstTyped *) symbol_resolve((*node)->token);
+ *node = (AstTyped *) symbol_resolve(semstate.curr_scope, (*node)->token);
}
}
}
+static void symres_use_package(AstUsePackage* package) {
+ token_toggle_end(package->package->token);
+ Package* p = program_info_package_lookup(semstate.program, package->package->token->text);
+ token_toggle_end(package->package->token);
+
+ if (p == NULL) {
+ onyx_message_add(Msg_Type_Literal,
+ package->token->pos,
+ "package not found in included source files");
+ return;
+ }
+
+ if (p->scope == semstate.curr_scope) return;
+
+ if (package->alias != NULL) {
+ AstPackage *pac_node = onyx_ast_node_new(semstate.node_allocator, sizeof(AstPackage), Ast_Kind_Package);
+ pac_node->package = p;
+
+ symbol_introduce(semstate.curr_scope, package->alias, (AstNode *) pac_node);
+ }
+
+ if (package->only != NULL) {
+ bh_arr_each(OnyxToken *, tkn, package->only) {
+
+ AstNode* thing = symbol_resolve(p->scope, *tkn);
+ if (thing == NULL) {
+ onyx_message_add(Msg_Type_Literal,
+ (*tkn)->pos,
+ "not found in package");
+ return;
+ }
+ symbol_introduce(semstate.curr_scope, *tkn, thing);
+ }
+ }
+
+ if (package->alias == NULL && package->only == NULL)
+ scope_include(semstate.curr_scope, p->scope);
+}
+
void onyx_resolve_symbols() {
- semstate.global_scope = scope_create(semstate.node_allocator, NULL);
- scope_enter(semstate.global_scope);
+ semstate.curr_scope = semstate.program->global_scope;
// NOTE: Add types to global scope
BuiltinSymbol* bsym = (BuiltinSymbol *) &builtin_symbols[0];
while (bsym->sym != NULL) {
- symbol_builtin_introduce(bsym->sym, bsym->node);
+ symbol_builtin_introduce(semstate.curr_scope, bsym->sym, bsym->node);
bsym++;
}
- bh_arr_each(AstBinding *, binding, semstate.program->bindings)
- if (!symbol_introduce((*binding)->token, (*binding)->node)) return;
-
bh_arr_each(Entity, entity, semstate.program->entities) {
+ scope_enter(entity->scope);
+
switch (entity->type) {
+ case Entity_Type_Use_Package: symres_use_package(entity->use_package); break;
case Entity_Type_Function: symres_function(entity->function); break;
case Entity_Type_Overloaded_Function: symres_overloaded_function(entity->overloaded_function); break;
case Entity_Type_Global: symres_global(entity->global); break;
default: break;
}
+
+ scope_leave();
}
}
#include "onyxutils.h"
#include "onyxlex.h"
#include "onyxastnodes.h"
+#include "onyxmsgs.h"
bh_scratch global_scratch;
bh_allocator global_scratch_allocator;
static const char* ast_node_names[] = {
"ERROR",
+ "PACKAGE",
"PROGRAM",
"USE",
}
+void program_info_init(ProgramInfo* prog, bh_allocator alloc) {
+ prog->global_scope = scope_create(alloc, NULL);
+ bh_table_init(alloc, prog->packages, 16);
+
+ prog->entities = NULL;
+ bh_arr_new(alloc, prog->entities, 4);
+}
+
+Package* program_info_package_lookup(ProgramInfo* prog, char* package_name) {
+ if (bh_table_has(Package *, prog->packages, package_name)) {
+ return bh_table_get(Package *, prog->packages, package_name);
+ } else {
+ return NULL;
+ }
+}
+
+Package* program_info_package_lookup_or_create(ProgramInfo* prog, char* package_name, Scope* parent_scope, bh_allocator alloc) {
+ if (bh_table_has(Package *, prog->packages, package_name)) {
+ return bh_table_get(Package *, prog->packages, package_name);
+
+ } else {
+ Package* package = bh_alloc_item(alloc, Package);
+
+ char* pac_name = bh_alloc_array(alloc, char, strlen(package_name) + 1);
+ memcpy(pac_name, package_name, strlen(package_name) + 1);
+
+ package->name = pac_name;
+ package->scope = scope_create(alloc, parent_scope);
+
+ bh_table_put(Package *, prog->packages, pac_name, package);
+
+ return package;
+ }
+}
Scope* scope_create(bh_allocator a, Scope* parent) {
Scope* scope = bh_alloc_item(a, Scope);
return scope;
}
+void scope_include(Scope* target, Scope* source) {
+ bh_table_each_start(AstNode *, source->symbols);
+ symbol_raw_introduce(target, (char *) key, value->token->pos, value);
+ bh_table_each_end;
+}
+
+b32 symbol_introduce(Scope* scope, OnyxToken* tkn, AstNode* symbol) {
+ token_toggle_end(tkn);
+
+ b32 ret = symbol_raw_introduce(scope, tkn->text, tkn->pos, symbol);
+
+ token_toggle_end(tkn);
+ return ret;
+}
+
+b32 symbol_raw_introduce(Scope* scope, char* name, OnyxFilePos pos, AstNode* symbol) {
+
+ if (bh_table_has(AstNode *, scope->symbols, name)) {
+ onyx_message_add(Msg_Type_Redeclare_Symbol, pos, name);
+ return 0;
+ }
+
+ bh_table_put(AstNode *, scope->symbols, name, symbol);
+ return 1;
+}
+
+void symbol_builtin_introduce(Scope* scope, char* sym, AstNode *node) {
+ bh_table_put(AstNode *, scope->symbols, sym, node);
+}
+
+AstNode* symbol_resolve(Scope* start_scope, OnyxToken* tkn) {
+ token_toggle_end(tkn);
+
+ AstNode* res = NULL;
+ Scope* scope = start_scope;
+
+ while (res == NULL && scope != NULL) {
+ if (bh_table_has(AstNode *, scope->symbols, tkn->text)) {
+ res = bh_table_get(AstNode *, scope->symbols, tkn->text);
+ } else {
+ scope = scope->parent;
+ }
+ }
+
+ if (res == NULL ) {
+ onyx_message_add(Msg_Type_Unknown_Symbol,
+ tkn->pos,
+ tkn->text);
+
+ token_toggle_end(tkn);
+ return NULL;
+ }
+
+ if (res->kind == Ast_Kind_Symbol) {
+ token_toggle_end(tkn);
+ return symbol_resolve(start_scope, res->token);
+ }
+
+ token_toggle_end(tkn);
+ return res;
+}
+
+
void onyx_ast_print(AstNode* node, i32 indent) {
assert(0);
}