mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-30 09:54:45 +00:00
Update README.md
This commit is contained in:
37
README.md
37
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
# The Odin Programming Language
|
||||
|
||||
Odin is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
|
||||
The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
|
||||
* simplicity
|
||||
* high performance
|
||||
* built for modern systems
|
||||
@@ -18,6 +18,7 @@ Odin is fast, concise, readable, pragmatic and open sourced. It is designed with
|
||||
* [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM)
|
||||
* [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s)
|
||||
* [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78)
|
||||
* [when, for, & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
|
||||
|
||||
## Requirements to build and run
|
||||
|
||||
@@ -30,27 +31,27 @@ Odin is fast, concise, readable, pragmatic and open sourced. It is designed with
|
||||
## Warnings
|
||||
|
||||
* This is still highly in development and the language's design is quite volatile.
|
||||
* Syntax is definitely not fixed
|
||||
* Syntax is not fixed.
|
||||
|
||||
## Roadmap
|
||||
|
||||
Not in any particular order
|
||||
|
||||
* Custom backend to replace LLVM
|
||||
- Improve SSA design to accommodate for lowering to a "bytecode"
|
||||
- SSA optimizations
|
||||
- COFF generation
|
||||
- linker
|
||||
* Type safe "macros"
|
||||
* Documentation generator for "Entities"
|
||||
* Multiple architecture support
|
||||
* Inline assembly
|
||||
* Linking options
|
||||
- Executable
|
||||
- Static/Dynamic Library
|
||||
* Debug information
|
||||
* Compile Time Execution (CTE)
|
||||
- More metaprogramming madness
|
||||
- Compiler as a library
|
||||
- AST inspection and modification
|
||||
* CTE-based build system
|
||||
* Replace LLVM backend with my own custom backend
|
||||
* Improve SSA design to accommodate for lowering to a "bytecode"
|
||||
* SSA optimizations
|
||||
* Parametric Polymorphism ("Generics")
|
||||
* Documentation Generator for "Entities"
|
||||
* Multiple Architecture support
|
||||
* Language level atomics and concurrency support
|
||||
* Debug Information
|
||||
- pdb format too
|
||||
* Command line tooling
|
||||
* Compiler internals:
|
||||
* Command Line Tooling
|
||||
* Compiler Internals:
|
||||
- Big numbers library
|
||||
|
||||
- Multithreading for performance increase
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
set exe_name=odin.exe
|
||||
|
||||
:: Debug = 0, Release = 1
|
||||
set release_mode=0
|
||||
set release_mode=1
|
||||
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
|
||||
279
code/demo.odin
279
code/demo.odin
@@ -1,9 +1,282 @@
|
||||
#import "fmt.odin";
|
||||
#import "utf8.odin";
|
||||
// #import "atomic.odin";
|
||||
// #import "hash.odin";
|
||||
// #import "math.odin";
|
||||
// #import "mem.odin";
|
||||
// #import "opengl.odin";
|
||||
// #import "os.odin";
|
||||
// #import "sync.odin";
|
||||
// #import win32 "sys/windows.odin";
|
||||
|
||||
main :: proc() {
|
||||
fmt.println(foo("FOO"));
|
||||
// syntax();
|
||||
procedure_overloading();
|
||||
}
|
||||
|
||||
foo :: proc(test: string, test1: string, args: ...any) { }
|
||||
syntax :: proc() {
|
||||
// Cyclic type checking
|
||||
// Uncomment to see the error
|
||||
// A :: struct {b: B};
|
||||
// B :: struct {a: A};
|
||||
|
||||
foo :: proc(test: string) { }
|
||||
x: int;
|
||||
y := cast(f32)x;
|
||||
z := transmute(u32)y;
|
||||
// down_cast, union_cast are similar too
|
||||
|
||||
|
||||
|
||||
// Basic directives
|
||||
fmt.printf("Basic directives = %s(%d): %s\n", #file, #line, #procedure);
|
||||
// NOTE: new and improved `printf`
|
||||
// TODO: It does need accurate float printing
|
||||
|
||||
|
||||
|
||||
// record fields use the same syntax a procedure signatures
|
||||
Thing1 :: struct {
|
||||
x: f32,
|
||||
y: int,
|
||||
z: ^[]int,
|
||||
};
|
||||
Thing2 :: struct {x: f32, y: int, z: ^[]int};
|
||||
|
||||
// Slice interals are now just a `ptr+count`
|
||||
slice: []int; compile_assert(size_of_val(slice) == 2*size_of(int));
|
||||
|
||||
// Helper type - Help the reader understand what it is quicker
|
||||
My_Int :: type int;
|
||||
My_Proc :: type proc(int) -> f32;
|
||||
|
||||
|
||||
// All declarations with : are either variable or constant
|
||||
// To make these declarations syntactically consistent
|
||||
v_variable := 123;
|
||||
c_constant :: 123;
|
||||
c_type1 :: int;
|
||||
c_type2 :: []int;
|
||||
c_proc :: proc() { /* code here */ };
|
||||
|
||||
|
||||
x += 1;
|
||||
x -= 1;
|
||||
// ++ and -- have been removed
|
||||
// x++;
|
||||
// x--;
|
||||
// Question: Should they be added again?
|
||||
// They were removed as they are redundant and statements, not expressions
|
||||
// like in C/C++
|
||||
|
||||
|
||||
// You can now build files as a `.dll`
|
||||
// `odin build_dll demo.odin`
|
||||
|
||||
|
||||
// New vector syntax
|
||||
u, v: [vector 3]f32;
|
||||
v[0] = 123;
|
||||
v.x = 123; // valid for all vectors with count 1 to 4
|
||||
|
||||
// Next part
|
||||
prefixes();
|
||||
}
|
||||
|
||||
|
||||
Prefix_Type :: struct {x: int, y: f32, z: rawptr};
|
||||
|
||||
thread_local my_tls: Prefix_Type;
|
||||
|
||||
prefixes :: proc() {
|
||||
using var: Prefix_Type;
|
||||
immutable const := Prefix_Type{1, 2, nil};
|
||||
var.x = 123;
|
||||
x = 123;
|
||||
// const.x = 123; // const is immutable
|
||||
|
||||
|
||||
|
||||
foo :: proc(using immutable pt: Prefix_Type, immutable int_ptr: ^int) {
|
||||
// int_ptr = nil; // Not valid
|
||||
int_ptr^ = 123; // Is valid
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Same as C99's `restrict`
|
||||
bar :: proc(no_alias a, b: ^int) {
|
||||
// Assumes a never equals b so it can perform optimizations with that fact
|
||||
}
|
||||
|
||||
|
||||
when_statements();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
when_statements :: proc() {
|
||||
X :: 123 + 12;
|
||||
Y :: X/5;
|
||||
COND :: Y > 0;
|
||||
|
||||
when COND {
|
||||
fmt.println("Y > 0");
|
||||
} else {
|
||||
fmt.println("Y <= 0");
|
||||
}
|
||||
|
||||
|
||||
when false {
|
||||
this_code_does_not_exist(123, 321);
|
||||
but_its_syntax_is_valid();
|
||||
x :: ^^^^int;
|
||||
}
|
||||
|
||||
foreign_procedures();
|
||||
}
|
||||
|
||||
#foreign_system_library win32_user "user32.lib" when ODIN_OS == "windows";
|
||||
// NOTE: This is done on purpose for two reasons:
|
||||
// * Makes it clear where the platform specific stuff is
|
||||
// * Removes the need to solve the travelling salesman problem when importing files :P
|
||||
|
||||
foreign_procedures :: proc() {
|
||||
ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user;
|
||||
show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user "ShowWindow";
|
||||
// NOTE: If that library doesn't get used, it doesn't get linked with
|
||||
// NOTE: There is not link checking yet to see if that procedure does come from that library
|
||||
|
||||
// See sys/windows.odin for more examples
|
||||
|
||||
special_expressions();
|
||||
}
|
||||
|
||||
special_expressions :: proc() {
|
||||
// Block expression
|
||||
x := {
|
||||
a: f32 = 123;
|
||||
b := a-123;
|
||||
c := b/a;
|
||||
give c;
|
||||
}; // semicolon is required as it's an expression
|
||||
|
||||
y := if x < 50 {
|
||||
give x;
|
||||
} else {
|
||||
// TODO: Type cohesion is not yet finished
|
||||
give 123;
|
||||
}; // semicolon is required as it's an expression
|
||||
|
||||
|
||||
// This is allows for inline blocks of code and will be a useful feature to have when
|
||||
// macros will be implemented into the language
|
||||
|
||||
loops();
|
||||
}
|
||||
|
||||
loops :: proc() {
|
||||
// The C-style for loop
|
||||
for i := 0; i < 123; i += 1 {
|
||||
break;
|
||||
}
|
||||
for i := 0; i < 123; {
|
||||
break;
|
||||
}
|
||||
for false {
|
||||
break;
|
||||
}
|
||||
for {
|
||||
break;
|
||||
}
|
||||
|
||||
for i in 0..<123 { // 123 exclusive
|
||||
}
|
||||
|
||||
for i in 0...122 { // 122 inclusive
|
||||
}
|
||||
|
||||
for val, idx in 12..<16 {
|
||||
fmt.println(val, idx);
|
||||
}
|
||||
|
||||
primes := [...]int{2, 3, 5, 7, 11, 13, 17, 19};
|
||||
|
||||
for p in primes {
|
||||
fmt.println(p);
|
||||
}
|
||||
|
||||
// Pointers to arrays, slices, or strings are allowed
|
||||
for _ in ^primes {
|
||||
// ignore the value and just iterate across it
|
||||
}
|
||||
|
||||
|
||||
|
||||
name := "你好,世界";
|
||||
fmt.println(name);
|
||||
for r in name {
|
||||
compile_assert(type_of_val(r) == rune);
|
||||
fmt.printf("%r\n", r);
|
||||
}
|
||||
|
||||
when false {
|
||||
for i, size := 0; i < name.count; i += size {
|
||||
r: rune;
|
||||
r, size = utf8.decode_rune(name[i:]);
|
||||
fmt.printf("%r\n", r);
|
||||
}
|
||||
}
|
||||
|
||||
procedure_overloading();
|
||||
}
|
||||
|
||||
|
||||
procedure_overloading :: proc() {
|
||||
THINGF :: 14451.1;
|
||||
THINGI :: 14451;
|
||||
|
||||
foo :: proc() {
|
||||
fmt.printf("Zero args\n");
|
||||
}
|
||||
foo :: proc(i: int) {
|
||||
fmt.printf("int arg, i=%d\n", i);
|
||||
}
|
||||
foo :: proc(f: f64) {
|
||||
i := cast(int)f;
|
||||
fmt.printf("f64 arg, f=%d\n", i);
|
||||
}
|
||||
|
||||
foo();
|
||||
foo(THINGF);
|
||||
// foo(THINGI); // 14451 is just a number so it could go to either procedures
|
||||
foo(cast(int)THINGI);
|
||||
|
||||
|
||||
|
||||
|
||||
foo :: proc(x: ^i32) -> (int, int) {
|
||||
fmt.println("^int");
|
||||
return 123, cast(int)(x^);
|
||||
}
|
||||
foo :: proc(x: rawptr) {
|
||||
fmt.println("rawptr");
|
||||
}
|
||||
|
||||
|
||||
a: i32 = 123;
|
||||
b: f32;
|
||||
c: rawptr;
|
||||
fmt.println(foo(^a));
|
||||
foo(^b);
|
||||
foo(c);
|
||||
// foo(nil); // nil could go to numerous types thus the ambiguity
|
||||
|
||||
f: proc();
|
||||
f = foo; // The correct `foo` to chosen
|
||||
f();
|
||||
|
||||
|
||||
// See math.odin and atomic.odin for more examples
|
||||
}
|
||||
|
||||
282
code/old_demos/demo005.odin
Normal file
282
code/old_demos/demo005.odin
Normal file
@@ -0,0 +1,282 @@
|
||||
#import "fmt.odin";
|
||||
#import "utf8.odin";
|
||||
// #import "atomic.odin";
|
||||
// #import "hash.odin";
|
||||
// #import "math.odin";
|
||||
// #import "mem.odin";
|
||||
// #import "opengl.odin";
|
||||
// #import "os.odin";
|
||||
// #import "sync.odin";
|
||||
// #import win32 "sys/windows.odin";
|
||||
|
||||
main :: proc() {
|
||||
// syntax();
|
||||
procedure_overloading();
|
||||
}
|
||||
|
||||
syntax :: proc() {
|
||||
// Cyclic type checking
|
||||
// Uncomment to see the error
|
||||
// A :: struct {b: B};
|
||||
// B :: struct {a: A};
|
||||
|
||||
x: int;
|
||||
y := cast(f32)x;
|
||||
z := transmute(u32)y;
|
||||
// down_cast, union_cast are similar too
|
||||
|
||||
|
||||
|
||||
// Basic directives
|
||||
fmt.printf("Basic directives = %s(%d): %s\n", #file, #line, #procedure);
|
||||
// NOTE: new and improved `printf`
|
||||
// TODO: It does need accurate float printing
|
||||
|
||||
|
||||
|
||||
// record fields use the same syntax a procedure signatures
|
||||
Thing1 :: struct {
|
||||
x: f32,
|
||||
y: int,
|
||||
z: ^[]int,
|
||||
};
|
||||
Thing2 :: struct {x: f32, y: int, z: ^[]int};
|
||||
|
||||
// Slice interals are now just a `ptr+count`
|
||||
slice: []int; compile_assert(size_of_val(slice) == 2*size_of(int));
|
||||
|
||||
// Helper type - Help the reader understand what it is quicker
|
||||
My_Int :: type int;
|
||||
My_Proc :: type proc(int) -> f32;
|
||||
|
||||
|
||||
// All declarations with : are either variable or constant
|
||||
// To make these declarations syntactically consistent
|
||||
v_variable := 123;
|
||||
c_constant :: 123;
|
||||
c_type1 :: int;
|
||||
c_type2 :: []int;
|
||||
c_proc :: proc() { /* code here */ };
|
||||
|
||||
|
||||
x += 1;
|
||||
x -= 1;
|
||||
// ++ and -- have been removed
|
||||
// x++;
|
||||
// x--;
|
||||
// Question: Should they be added again?
|
||||
// They were removed as they are redundant and statements, not expressions
|
||||
// like in C/C++
|
||||
|
||||
|
||||
// You can now build files as a `.dll`
|
||||
// `odin build_dll demo.odin`
|
||||
|
||||
|
||||
// New vector syntax
|
||||
u, v: [vector 3]f32;
|
||||
v[0] = 123;
|
||||
v.x = 123; // valid for all vectors with count 1 to 4
|
||||
|
||||
// Next part
|
||||
prefixes();
|
||||
}
|
||||
|
||||
|
||||
Prefix_Type :: struct {x: int, y: f32, z: rawptr};
|
||||
|
||||
thread_local my_tls: Prefix_Type;
|
||||
|
||||
prefixes :: proc() {
|
||||
using var: Prefix_Type;
|
||||
immutable const := Prefix_Type{1, 2, nil};
|
||||
var.x = 123;
|
||||
x = 123;
|
||||
// const.x = 123; // const is immutable
|
||||
|
||||
|
||||
|
||||
foo :: proc(using immutable pt: Prefix_Type, immutable int_ptr: ^int) {
|
||||
// int_ptr = nil; // Not valid
|
||||
int_ptr^ = 123; // Is valid
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Same as C99's `restrict`
|
||||
bar :: proc(no_alias a, b: ^int) {
|
||||
// Assumes a never equals b so it can perform optimizations with that fact
|
||||
}
|
||||
|
||||
|
||||
when_statements();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
when_statements :: proc() {
|
||||
X :: 123 + 12;
|
||||
Y :: X/5;
|
||||
COND :: Y > 0;
|
||||
|
||||
when COND {
|
||||
fmt.println("Y > 0");
|
||||
} else {
|
||||
fmt.println("Y <= 0");
|
||||
}
|
||||
|
||||
|
||||
when false {
|
||||
this_code_does_not_exist(123, 321);
|
||||
but_its_syntax_is_valid();
|
||||
x :: ^^^^int;
|
||||
}
|
||||
|
||||
foreign_procedures();
|
||||
}
|
||||
|
||||
#foreign_system_library win32_user "user32.lib" when ODIN_OS == "windows";
|
||||
// NOTE: This is done on purpose for two reasons:
|
||||
// * Makes it clear where the platform specific stuff is
|
||||
// * Removes the need to solve the travelling salesman problem when importing files :P
|
||||
|
||||
foreign_procedures :: proc() {
|
||||
ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user;
|
||||
show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user "ShowWindow";
|
||||
// NOTE: If that library doesn't get used, it doesn't get linked with
|
||||
// NOTE: There is not link checking yet to see if that procedure does come from that library
|
||||
|
||||
// See sys/windows.odin for more examples
|
||||
|
||||
special_expressions();
|
||||
}
|
||||
|
||||
special_expressions :: proc() {
|
||||
// Block expression
|
||||
x := {
|
||||
a: f32 = 123;
|
||||
b := a-123;
|
||||
c := b/a;
|
||||
give c;
|
||||
}; // semicolon is required as it's an expression
|
||||
|
||||
y := if x < 50 {
|
||||
give x;
|
||||
} else {
|
||||
// TODO: Type cohesion is not yet finished
|
||||
give 123;
|
||||
}; // semicolon is required as it's an expression
|
||||
|
||||
|
||||
// This is allows for inline blocks of code and will be a useful feature to have when
|
||||
// macros will be implemented into the language
|
||||
|
||||
loops();
|
||||
}
|
||||
|
||||
loops :: proc() {
|
||||
// The C-style for loop
|
||||
for i := 0; i < 123; i += 1 {
|
||||
break;
|
||||
}
|
||||
for i := 0; i < 123; {
|
||||
break;
|
||||
}
|
||||
for false {
|
||||
break;
|
||||
}
|
||||
for {
|
||||
break;
|
||||
}
|
||||
|
||||
for i in 0..<123 { // 123 exclusive
|
||||
}
|
||||
|
||||
for i in 0...122 { // 122 inclusive
|
||||
}
|
||||
|
||||
for val, idx in 12..<16 {
|
||||
fmt.println(val, idx);
|
||||
}
|
||||
|
||||
primes := [...]int{2, 3, 5, 7, 11, 13, 17, 19};
|
||||
|
||||
for p in primes {
|
||||
fmt.println(p);
|
||||
}
|
||||
|
||||
// Pointers to arrays, slices, or strings are allowed
|
||||
for _ in ^primes {
|
||||
// ignore the value and just iterate across it
|
||||
}
|
||||
|
||||
|
||||
|
||||
name := "你好,世界";
|
||||
fmt.println(name);
|
||||
for r in name {
|
||||
compile_assert(type_of_val(r) == rune);
|
||||
fmt.printf("%r\n", r);
|
||||
}
|
||||
|
||||
when false {
|
||||
for i, size := 0; i < name.count; i += size {
|
||||
r: rune;
|
||||
r, size = utf8.decode_rune(name[i:]);
|
||||
fmt.printf("%r\n", r);
|
||||
}
|
||||
}
|
||||
|
||||
procedure_overloading();
|
||||
}
|
||||
|
||||
|
||||
procedure_overloading :: proc() {
|
||||
THINGF :: 14451.1;
|
||||
THINGI :: 14451;
|
||||
|
||||
foo :: proc() {
|
||||
fmt.printf("Zero args\n");
|
||||
}
|
||||
foo :: proc(i: int) {
|
||||
fmt.printf("int arg, i=%d\n", i);
|
||||
}
|
||||
foo :: proc(f: f64) {
|
||||
i := cast(int)f;
|
||||
fmt.printf("f64 arg, f=%d\n", i);
|
||||
}
|
||||
|
||||
foo();
|
||||
foo(THINGF);
|
||||
// foo(THINGI); // 14451 is just a number so it could go to either procedures
|
||||
foo(cast(int)THINGI);
|
||||
|
||||
|
||||
|
||||
|
||||
foo :: proc(x: ^i32) -> (int, int) {
|
||||
fmt.println("^int");
|
||||
return 123, cast(int)(x^);
|
||||
}
|
||||
foo :: proc(x: rawptr) {
|
||||
fmt.println("rawptr");
|
||||
}
|
||||
|
||||
|
||||
a: i32 = 123;
|
||||
b: f32;
|
||||
c: rawptr;
|
||||
fmt.println(foo(^a));
|
||||
foo(^b);
|
||||
foo(c);
|
||||
// foo(nil); // nil could go to numerous types thus the ambiguity
|
||||
|
||||
f: proc();
|
||||
f = foo; // The correct `foo` to chosen
|
||||
f();
|
||||
|
||||
|
||||
// See math.odin and atomic.odin for more examples
|
||||
}
|
||||
Reference in New Issue
Block a user