mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Fix utf8 stuff, Allow _ in numbers, Begin writing next demo code.
This commit is contained in:
+255
-26
@@ -1,34 +1,241 @@
|
|||||||
#import "atomic.odin";
|
|
||||||
#import "fmt.odin";
|
#import "fmt.odin";
|
||||||
#import "hash.odin";
|
|
||||||
#import "math.odin";
|
|
||||||
#import "mem.odin";
|
|
||||||
#import "opengl.odin";
|
|
||||||
#import "os.odin";
|
|
||||||
#import win32 "sys/windows.odin";
|
|
||||||
#import "sync.odin";
|
|
||||||
#import "utf8.odin";
|
#import "utf8.odin";
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
foo :: proc(x: ^i32) -> (int, int) {
|
syntax();
|
||||||
fmt.println("^int");
|
}
|
||||||
return 123, cast(int)(x^);
|
|
||||||
}
|
syntax :: proc() {
|
||||||
foo :: proc(x: rawptr) {
|
// Cyclic type checking
|
||||||
fmt.println("rawptr");
|
// 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 as 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 not just a `ptr+count`
|
||||||
|
slice: []int; compile_assert(size_of_val(slice) == 2*size_of(int));
|
||||||
|
|
||||||
|
// Helper type - Help the reader understand that 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--;
|
||||||
|
|
||||||
|
|
||||||
|
// You can now build files as a `.dll`
|
||||||
|
// `odin build_dll demo.odin`
|
||||||
|
|
||||||
|
|
||||||
|
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
THINGI :: 14451;
|
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
#import "atomic.odin" when ODIN_OS == "windows";
|
||||||
|
#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
|
||||||
|
|
||||||
|
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
|
||||||
|
// E.g. this constant "number" should be able to be cast to a `f32` automatically
|
||||||
|
give cast(f32)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() {
|
||||||
|
|
||||||
|
// while loops
|
||||||
|
while true {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while x := 123; x < 124 {
|
||||||
|
x += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
This only C-style for loop has now been removed
|
||||||
|
|
||||||
|
for i := 0; i < 123; i += 1 {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
for i : 0..<123 {
|
||||||
|
}
|
||||||
|
|
||||||
|
for i : 0...122 {
|
||||||
|
}
|
||||||
|
|
||||||
|
for val, idx : 12..<16 {
|
||||||
|
fmt.println(val, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
primes := [...]int{2, 3, 5, 7, 11, 13, 17, 19};
|
||||||
|
|
||||||
|
for p : primes {
|
||||||
|
fmt.println(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointers to arrays, slices, or strings are allowed
|
||||||
|
for _ : ^primes {
|
||||||
|
// ignore the value and just iterate across it
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
name := "你好,世界";
|
||||||
|
fmt.println(name);
|
||||||
|
for r : name {
|
||||||
|
compile_assert(type_of_val(r) == rune);
|
||||||
|
fmt.printf("%r\n", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
when false {
|
||||||
|
while i := 0; i < name.count {
|
||||||
|
r, size := utf8.decode_rune(name[i:]);
|
||||||
|
i += size;
|
||||||
|
fmt.printf("%c\n", r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Emulate a C-style loop (not exactly the same though)
|
||||||
|
while x := 0; x < 10 {
|
||||||
|
defer x += 2;
|
||||||
|
|
||||||
|
/* rest of the code */
|
||||||
|
// If `break` is used, the `defer` is still called so it's not the same
|
||||||
|
// as a C-style for loop
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
procedure_overloading();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
procedure_overloading :: proc() {
|
||||||
THINGF :: 14451.1;
|
THINGF :: 14451.1;
|
||||||
|
THINGI :: 14451;
|
||||||
a: i32 = #line;
|
|
||||||
b: f32;
|
|
||||||
c: rawptr;
|
|
||||||
fmt.println(foo(^a));
|
|
||||||
foo(^b);
|
|
||||||
foo(c);
|
|
||||||
// foo(nil);
|
|
||||||
atomic.store(^a, 1);
|
|
||||||
|
|
||||||
foo :: proc() {
|
foo :: proc() {
|
||||||
fmt.printf("Zero args\n");
|
fmt.printf("Zero args\n");
|
||||||
@@ -42,11 +249,33 @@ main :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foo();
|
foo();
|
||||||
// foo(THINGI);
|
|
||||||
foo(THINGF);
|
foo(THINGF);
|
||||||
|
// foo(THINGI);
|
||||||
foo(cast(int)THINGI);
|
foo(cast(int)THINGI);
|
||||||
fmt.println(THINGI);
|
|
||||||
fmt.println(THINGF);
|
fmt.println(THINGF);
|
||||||
|
fmt.println(THINGI);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
foo :: proc(x: ^i32) -> (int, int) {
|
||||||
|
fmt.println("^int");
|
||||||
|
return 123, cast(int)(x^);
|
||||||
|
}
|
||||||
|
foo :: proc(x: rawptr) {
|
||||||
|
fmt.println("rawptr");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a: i32 = #line;
|
||||||
|
b: f32;
|
||||||
|
c: rawptr;
|
||||||
|
fmt.println(foo(^a));
|
||||||
|
foo(^b);
|
||||||
|
foo(c);
|
||||||
|
// foo(nil);
|
||||||
|
atomic.store(^a, 1);
|
||||||
|
|
||||||
|
|
||||||
f: proc();
|
f: proc();
|
||||||
f = foo;
|
f = foo;
|
||||||
|
|||||||
+5
-4
@@ -233,7 +233,7 @@ bprint :: proc(buf: ^Buffer, args: ...any) -> int {
|
|||||||
for arg, i : args {
|
for arg, i : args {
|
||||||
is_string := arg.data != nil && is_type_string(arg.type_info);
|
is_string := arg.data != nil && is_type_string(arg.type_info);
|
||||||
if i > 0 && !is_string && !prev_string {
|
if i > 0 && !is_string && !prev_string {
|
||||||
buffer_write_rune(buf, ' ');
|
buffer_write_byte(buf, ' ');
|
||||||
}
|
}
|
||||||
fmt_value(^fi, args[i], 'v');
|
fmt_value(^fi, args[i], 'v');
|
||||||
prev_string = is_string;
|
prev_string = is_string;
|
||||||
@@ -247,11 +247,11 @@ bprintln :: proc(buf: ^Buffer, args: ...any) -> int {
|
|||||||
|
|
||||||
for arg, i : args {
|
for arg, i : args {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buffer_write_rune(buf, ' ');
|
buffer_write_byte(buf, ' ');
|
||||||
}
|
}
|
||||||
fmt_value(^fi, args[i], 'v');
|
fmt_value(^fi, args[i], 'v');
|
||||||
}
|
}
|
||||||
buffer_write_rune(buf, '\n');
|
buffer_write_byte(buf, '\n');
|
||||||
return buf.length;
|
return buf.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,7 +532,8 @@ fmt_int :: proc(fi: ^Fmt_Info, u: u64, signed: bool, verb: rune) {
|
|||||||
case 'd': fmt_integer(fi, u, 10, signed, __DIGITS_LOWER);
|
case 'd': fmt_integer(fi, u, 10, signed, __DIGITS_LOWER);
|
||||||
case 'x': fmt_integer(fi, u, 16, signed, __DIGITS_LOWER);
|
case 'x': fmt_integer(fi, u, 16, signed, __DIGITS_LOWER);
|
||||||
case 'X': fmt_integer(fi, u, 16, signed, __DIGITS_UPPER);
|
case 'X': fmt_integer(fi, u, 16, signed, __DIGITS_UPPER);
|
||||||
case 'c': fmt_rune(fi, cast(rune)u);
|
case 'c', 'r':
|
||||||
|
fmt_rune(fi, cast(rune)u);
|
||||||
case 'U':
|
case 'U':
|
||||||
r := cast(rune)u;
|
r := cast(rune)u;
|
||||||
if r < 0 || r > utf8.MAX_RUNE {
|
if r < 0 || r > utf8.MAX_RUNE {
|
||||||
|
|||||||
+39
-26
@@ -8,9 +8,29 @@ UTF_MAX :: 4;
|
|||||||
SURROGATE_MIN :: 0xd800;
|
SURROGATE_MIN :: 0xd800;
|
||||||
SURROGATE_MAX :: 0xdfff;
|
SURROGATE_MAX :: 0xdfff;
|
||||||
|
|
||||||
|
T1 :: 0b0000_0000;
|
||||||
|
TX :: 0b1000_0000;
|
||||||
|
T2 :: 0b1100_0000;
|
||||||
|
T3 :: 0b1110_0000;
|
||||||
|
T4 :: 0b1111_0000;
|
||||||
|
T5 :: 0b1111_1000;
|
||||||
|
|
||||||
|
MASKX :: 0b0011_1111;
|
||||||
|
MASK2 :: 0b0001_1111;
|
||||||
|
MASK3 :: 0b0000_1111;
|
||||||
|
MASK4 :: 0b0000_0111;
|
||||||
|
|
||||||
|
RUNE1_MAX :: 1<<7 - 1;
|
||||||
|
RUNE2_MAX :: 1<<11 - 1;
|
||||||
|
RUNE3_MAX :: 1<<16 - 1;
|
||||||
|
|
||||||
|
// The default lowest and highest continuation byte.
|
||||||
|
LOCB :: 0b1000_0000;
|
||||||
|
HICB :: 0b1011_1111;
|
||||||
|
|
||||||
Accept_Range :: struct { lo, hi: u8 }
|
Accept_Range :: struct { lo, hi: u8 }
|
||||||
|
|
||||||
accept_ranges := [5]Accept_Range{
|
immutable accept_ranges := [5]Accept_Range{
|
||||||
{0x80, 0xbf},
|
{0x80, 0xbf},
|
||||||
{0xa0, 0xbf},
|
{0xa0, 0xbf},
|
||||||
{0x80, 0x9f},
|
{0x80, 0x9f},
|
||||||
@@ -18,7 +38,7 @@ accept_ranges := [5]Accept_Range{
|
|||||||
{0x80, 0x8f},
|
{0x80, 0x8f},
|
||||||
};
|
};
|
||||||
|
|
||||||
accept_sizes := [256]byte{
|
immutable accept_sizes := [256]byte{
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
||||||
@@ -68,7 +88,7 @@ encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
|||||||
buf[0] = 0xf0 | cast(byte)(r>>18);
|
buf[0] = 0xf0 | cast(byte)(r>>18);
|
||||||
buf[1] = 0x80 | cast(byte)(r>>12) & mask;
|
buf[1] = 0x80 | cast(byte)(r>>12) & mask;
|
||||||
buf[2] = 0x80 | cast(byte)(r>>6) & mask;
|
buf[2] = 0x80 | cast(byte)(r>>6) & mask;
|
||||||
buf[3] = 0x80 | cast(byte)r & mask;
|
buf[3] = 0x80 | cast(byte)r & mask;
|
||||||
return buf, 4;
|
return buf, 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,43 +97,36 @@ decode_rune :: proc(s: string) -> (rune, int) {
|
|||||||
if n < 1 {
|
if n < 1 {
|
||||||
return RUNE_ERROR, 0;
|
return RUNE_ERROR, 0;
|
||||||
}
|
}
|
||||||
b0 := s[0];
|
s0 := s[0];
|
||||||
x := accept_sizes[b0];
|
x := accept_sizes[s0];
|
||||||
if x >= 0xf0 {
|
if x >= 0xF0 {
|
||||||
mask := (cast(rune)x << 31) >> 31; // all zeros or all ones
|
mask := cast(rune)(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
|
||||||
return cast(rune)b0 &~ mask | RUNE_ERROR&mask, 1;
|
return cast(rune)(s[0])&~mask | RUNE_ERROR&mask, 1;
|
||||||
}
|
}
|
||||||
size := x & 7;
|
sz := x & 7;
|
||||||
ar := accept_ranges[x>>4];
|
accept := accept_ranges[x>>4];
|
||||||
if n < cast(int)size {
|
if n < cast(int)sz {
|
||||||
return RUNE_ERROR, 1;
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
b1 := s[1];
|
b1 := s[1];
|
||||||
if b1 < ar.lo || ar.hi < b1 {
|
if b1 < accept.lo || accept.hi < b1 {
|
||||||
return RUNE_ERROR, 1;
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
|
if sz == 2 {
|
||||||
MASK_X :: 0b00111111;
|
return cast(rune)(s0&MASK2)<<6 | cast(rune)(b1&MASKX), 2;
|
||||||
MASK_2 :: 0b00011111;
|
|
||||||
MASK_3 :: 0b00001111;
|
|
||||||
MASK_4 :: 0b00000111;
|
|
||||||
|
|
||||||
if size == 2 {
|
|
||||||
return cast(rune)(b0&MASK_2)<<6 | cast(rune)(b1&MASK_X), 2;
|
|
||||||
}
|
}
|
||||||
b2 := s[2];
|
b2 := s[2];
|
||||||
if b2 < 0x80 || 0xbf < b2 {
|
if b2 < LOCB || HICB < b2 {
|
||||||
return RUNE_ERROR, 1;
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
if size == 3 {
|
if sz == 3 {
|
||||||
return cast(rune)(b0&MASK_3)<<12 | cast(rune)(b1&MASK_X)<<6 | cast(rune)(b2&MASK_X), 3;
|
return cast(rune)(s0&MASK3)<<12 | cast(rune)(b1&MASKX)<<6 | cast(rune)(b2&MASKX), 3;
|
||||||
}
|
}
|
||||||
b3 := s[3];
|
b3 := s[3];
|
||||||
if b3 < 0x80 || 0xbf < b3 {
|
if b3 < LOCB || HICB < b3 {
|
||||||
return RUNE_ERROR, 1;
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
return cast(rune)(b0&MASK_4)<<18 | cast(rune)(b1&MASK_X)<<12 | cast(rune)(b3&MASK_X)<<6 | cast(rune)(b3&MASK_X), 4;
|
return cast(rune)(s0&MASK4)<<18 | cast(rune)(b1&MASKX)<<12 | cast(rune)(b2&MASKX)<<6 | cast(rune)(b3&MASKX), 4;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -477,9 +477,19 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
|||||||
void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
|
void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
|
||||||
GB_ASSERT(body->kind == AstNode_BlockStmt);
|
GB_ASSERT(body->kind == AstNode_BlockStmt);
|
||||||
|
|
||||||
|
String proc_name = {0};
|
||||||
|
if (token.kind == Token_Ident) {
|
||||||
|
proc_name = token.string;
|
||||||
|
} else {
|
||||||
|
// TODO(bill): Better name
|
||||||
|
proc_name = str_lit("(anonymous-procedure)");
|
||||||
|
}
|
||||||
|
|
||||||
CheckerContext old_context = c->context;
|
CheckerContext old_context = c->context;
|
||||||
c->context.scope = decl->scope;
|
c->context.scope = decl->scope;
|
||||||
c->context.decl = decl;
|
c->context.decl = decl;
|
||||||
|
c->context.proc_name = proc_name;
|
||||||
|
|
||||||
|
|
||||||
GB_ASSERT(type->kind == Type_Proc);
|
GB_ASSERT(type->kind == Type_Proc);
|
||||||
if (type->Proc.param_count > 0) {
|
if (type->Proc.param_count > 0) {
|
||||||
|
|||||||
+18
-2
@@ -3892,6 +3892,16 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
} else if (str_eq(bd->name, str_lit("line"))) {
|
} else if (str_eq(bd->name, str_lit("line"))) {
|
||||||
o->type = t_untyped_integer;
|
o->type = t_untyped_integer;
|
||||||
o->value = make_exact_value_integer(bd->token.pos.line);
|
o->value = make_exact_value_integer(bd->token.pos.line);
|
||||||
|
} else if (str_eq(bd->name, str_lit("procedure"))) {
|
||||||
|
if (c->proc_stack.count == 0) {
|
||||||
|
error_node(node, "#procedure may only be used within procedures");
|
||||||
|
o->type = t_untyped_string;
|
||||||
|
o->value = make_exact_value_string(str_lit(""));
|
||||||
|
} else {
|
||||||
|
o->type = t_untyped_string;
|
||||||
|
o->value = make_exact_value_string(c->context.proc_name);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
GB_PANIC("Unknown basic basic directive");
|
GB_PANIC("Unknown basic basic directive");
|
||||||
}
|
}
|
||||||
@@ -3962,9 +3972,11 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
goto error;
|
goto error;
|
||||||
} else if (operands.count == 1) {
|
} else if (operands.count == 1) {
|
||||||
Operand operand = operands.e[0];
|
Operand operand = operands.e[0];
|
||||||
if (type_hint != NULL) {
|
Type *th = type_hint != NULL ? type_hint : c->context.type_hint;
|
||||||
convert_to_typed(c, &operand, type_hint, 0);
|
if (th != NULL) {
|
||||||
|
convert_to_typed(c, &operand, th, 0);
|
||||||
}
|
}
|
||||||
|
// IMPORTANT NOTE(bill): This type could be untyped!!!
|
||||||
o->type = default_type(operand.type);
|
o->type = default_type(operand.type);
|
||||||
o->mode = Addressing_Value;
|
o->mode = Addressing_Value;
|
||||||
} else {
|
} else {
|
||||||
@@ -4012,10 +4024,14 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CheckerContext prev_context = c->context;
|
||||||
|
c->context.type_hint = type_hint;
|
||||||
check_open_scope(c, node);
|
check_open_scope(c, node);
|
||||||
check_stmt_list(c, be->stmts, Stmt_GiveAllowed);
|
check_stmt_list(c, be->stmts, Stmt_GiveAllowed);
|
||||||
check_close_scope(c);
|
check_close_scope(c);
|
||||||
|
|
||||||
|
c->context = prev_context;
|
||||||
|
|
||||||
AstNode *give_node = NULL;
|
AstNode *give_node = NULL;
|
||||||
if (!check_is_giving(node, &give_node) || give_node == NULL) {
|
if (!check_is_giving(node, &give_node) || give_node == NULL) {
|
||||||
error_node(node, "Missing give statement at end of block expression");
|
error_node(node, "Missing give statement at end of block expression");
|
||||||
|
|||||||
+4
-2
@@ -251,6 +251,8 @@ typedef struct CheckerContext {
|
|||||||
DeclInfo * decl;
|
DeclInfo * decl;
|
||||||
u32 stmt_state_flags;
|
u32 stmt_state_flags;
|
||||||
bool in_defer; // TODO(bill): Actually handle correctly
|
bool in_defer; // TODO(bill): Actually handle correctly
|
||||||
|
String proc_name;
|
||||||
|
Type * type_hint;
|
||||||
} CheckerContext;
|
} CheckerContext;
|
||||||
|
|
||||||
// NOTE(bill): Symbol tables
|
// NOTE(bill): Symbol tables
|
||||||
@@ -276,8 +278,8 @@ typedef struct Checker {
|
|||||||
BaseTypeSizes sizes;
|
BaseTypeSizes sizes;
|
||||||
Scope * global_scope;
|
Scope * global_scope;
|
||||||
Array(ProcedureInfo) procs; // NOTE(bill): Procedures to check
|
Array(ProcedureInfo) procs; // NOTE(bill): Procedures to check
|
||||||
Array(DelayedDecl) delayed_imports;
|
Array(DelayedDecl) delayed_imports;
|
||||||
Array(DelayedDecl) delayed_foreign_libraries;
|
Array(DelayedDecl) delayed_foreign_libraries;
|
||||||
|
|
||||||
|
|
||||||
gbArena arena;
|
gbArena arena;
|
||||||
|
|||||||
+45
-18
@@ -54,30 +54,57 @@ ExactValue make_exact_value_string(String string) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue make_exact_value_integer_from_string(String string) {
|
|
||||||
// TODO(bill): Allow for numbers with underscores in them
|
|
||||||
ExactValue result = {ExactValue_Integer};
|
|
||||||
i32 base = 10;
|
|
||||||
if (string.len > 2 && string.text[0] == '0') {
|
|
||||||
switch (string.text[1]) {
|
|
||||||
case 'b': base = 2; break;
|
|
||||||
case 'o': base = 8; break;
|
|
||||||
case 'd': base = 10; break;
|
|
||||||
case 'x': base = 16; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.value_integer = gb_str_to_i64(cast(char *)string.text, NULL, base);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExactValue make_exact_value_integer(i64 i) {
|
ExactValue make_exact_value_integer(i64 i) {
|
||||||
ExactValue result = {ExactValue_Integer};
|
ExactValue result = {ExactValue_Integer};
|
||||||
result.value_integer = i;
|
result.value_integer = i;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExactValue make_exact_value_integer_from_string(String string) {
|
||||||
|
// TODO(bill): Allow for numbers with underscores in them
|
||||||
|
i32 base = 10;
|
||||||
|
bool has_prefix = false;
|
||||||
|
if (string.len > 2 && string.text[0] == '0') {
|
||||||
|
switch (string.text[1]) {
|
||||||
|
case 'b': base = 2; has_prefix = true; break;
|
||||||
|
case 'o': base = 8; has_prefix = true; break;
|
||||||
|
case 'd': base = 10; has_prefix = true; break;
|
||||||
|
case 'x': base = 16; has_prefix = true; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *text = string.text;
|
||||||
|
isize len = string.len;
|
||||||
|
if (has_prefix) {
|
||||||
|
text += 2;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
i64 result = 0;
|
||||||
|
for (isize i = 0; i < len; i++) {
|
||||||
|
Rune r = cast(Rune)text[i];
|
||||||
|
if (r == '_') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
i64 v = 0;
|
||||||
|
if (gb_char_is_digit(r)) {
|
||||||
|
v = r - '0';
|
||||||
|
} else if (gb_char_is_hex_digit(r)) {
|
||||||
|
v = gb_hex_digit_to_int(r);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result *= base;
|
||||||
|
result += v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return make_exact_value_integer(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ExactValue make_exact_value_float_from_string(String string) {
|
ExactValue make_exact_value_float_from_string(String string) {
|
||||||
// TODO(bill): Allow for numbers with underscores in them
|
// TODO(bill): Allow for numbers with underscores in them
|
||||||
ExactValue result = {ExactValue_Float};
|
ExactValue result = {ExactValue_Float};
|
||||||
|
|||||||
+4
-5
@@ -1770,11 +1770,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
|||||||
case Token_Hash: {
|
case Token_Hash: {
|
||||||
Token token = expect_token(f, Token_Hash);
|
Token token = expect_token(f, Token_Hash);
|
||||||
Token name = expect_token(f, Token_Ident);
|
Token name = expect_token(f, Token_Ident);
|
||||||
if (str_eq(name.string, str_lit("file"))) {
|
if (str_eq(name.string, str_lit("run"))) {
|
||||||
return make_basic_directive(f, token, name.string);
|
|
||||||
} else if (str_eq(name.string, str_lit("line"))) {
|
|
||||||
return make_basic_directive(f, token, name.string);
|
|
||||||
} else if (str_eq(name.string, str_lit("run"))) {
|
|
||||||
AstNode *expr = parse_expr(f, false);
|
AstNode *expr = parse_expr(f, false);
|
||||||
operand = make_run_expr(f, token, name, expr);
|
operand = make_run_expr(f, token, name, expr);
|
||||||
if (unparen_expr(expr)->kind != AstNode_CallExpr) {
|
if (unparen_expr(expr)->kind != AstNode_CallExpr) {
|
||||||
@@ -1782,6 +1778,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
|||||||
operand = make_bad_expr(f, token, f->curr_token);
|
operand = make_bad_expr(f, token, f->curr_token);
|
||||||
}
|
}
|
||||||
warning(token, "#run is not yet implemented");
|
warning(token, "#run is not yet implemented");
|
||||||
|
} else if (str_eq(name.string, str_lit("file"))) { return make_basic_directive(f, token, name.string);
|
||||||
|
} else if (str_eq(name.string, str_lit("line"))) { return make_basic_directive(f, token, name.string);
|
||||||
|
} else if (str_eq(name.string, str_lit("procedure"))) { return make_basic_directive(f, token, name.string);
|
||||||
} else {
|
} else {
|
||||||
operand = make_tag_expr(f, token, name, parse_expr(f, false));
|
operand = make_tag_expr(f, token, name, parse_expr(f, false));
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-15
@@ -462,12 +462,15 @@ gb_inline i32 digit_value(Rune r) {
|
|||||||
return 16; // NOTE(bill): Larger than highest possible
|
return 16; // NOTE(bill): Larger than highest possible
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_inline void scan_mantissa(Tokenizer *t, i32 base) {
|
gb_inline void scan_mantissa(Tokenizer *t, i32 base, bool allow_underscore) {
|
||||||
// TODO(bill): Allow for underscores in numbers as a number separator
|
if (allow_underscore) {
|
||||||
// TODO(bill): Is this a good idea?
|
while (digit_value(t->curr_rune) < base || t->curr_rune == '_') {
|
||||||
// while (digit_value(t->curr_rune) < base || t->curr_rune == '_')
|
advance_to_next_rune(t);
|
||||||
while (digit_value(t->curr_rune) < base) {
|
}
|
||||||
advance_to_next_rune(t);
|
} else {
|
||||||
|
while (digit_value(t->curr_rune) < base) {
|
||||||
|
advance_to_next_rune(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +485,7 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
|||||||
|
|
||||||
if (seen_decimal_point) {
|
if (seen_decimal_point) {
|
||||||
token.kind = Token_Float;
|
token.kind = Token_Float;
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, true);
|
||||||
goto exponent;
|
goto exponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,31 +494,31 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
|||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
if (t->curr_rune == 'b') { // Binary
|
if (t->curr_rune == 'b') { // Binary
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_mantissa(t, 2);
|
scan_mantissa(t, 2, true);
|
||||||
if (t->curr - prev <= 2) {
|
if (t->curr - prev <= 2) {
|
||||||
token.kind = Token_Invalid;
|
token.kind = Token_Invalid;
|
||||||
}
|
}
|
||||||
} else if (t->curr_rune == 'o') { // Octal
|
} else if (t->curr_rune == 'o') { // Octal
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_mantissa(t, 8);
|
scan_mantissa(t, 8, true);
|
||||||
if (t->curr - prev <= 2) {
|
if (t->curr - prev <= 2) {
|
||||||
token.kind = Token_Invalid;
|
token.kind = Token_Invalid;
|
||||||
}
|
}
|
||||||
} else if (t->curr_rune == 'd') { // Decimal
|
} else if (t->curr_rune == 'd') { // Decimal
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, true);
|
||||||
if (t->curr - prev <= 2) {
|
if (t->curr - prev <= 2) {
|
||||||
token.kind = Token_Invalid;
|
token.kind = Token_Invalid;
|
||||||
}
|
}
|
||||||
} else if (t->curr_rune == 'x') { // Hexadecimal
|
} else if (t->curr_rune == 'x') { // Hexadecimal
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_mantissa(t, 16);
|
scan_mantissa(t, 16, true);
|
||||||
if (t->curr - prev <= 2) {
|
if (t->curr - prev <= 2) {
|
||||||
token.kind = Token_Invalid;
|
token.kind = Token_Invalid;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
seen_decimal_point = false;
|
seen_decimal_point = false;
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, true);
|
||||||
|
|
||||||
if (t->curr_rune == '.' || t->curr_rune == 'e' || t->curr_rune == 'E') {
|
if (t->curr_rune == '.' || t->curr_rune == 'e' || t->curr_rune == 'E') {
|
||||||
seen_decimal_point = true;
|
seen_decimal_point = true;
|
||||||
@@ -527,7 +530,7 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, true);
|
||||||
|
|
||||||
fraction:
|
fraction:
|
||||||
if (t->curr_rune == '.') {
|
if (t->curr_rune == '.') {
|
||||||
@@ -540,7 +543,7 @@ fraction:
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
token.kind = Token_Float;
|
token.kind = Token_Float;
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
exponent:
|
exponent:
|
||||||
@@ -550,7 +553,7 @@ exponent:
|
|||||||
if (t->curr_rune == '-' || t->curr_rune == '+') {
|
if (t->curr_rune == '-' || t->curr_rune == '+') {
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
}
|
}
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
|||||||
Reference in New Issue
Block a user