├── LICENSE ├── Odin.cloc ├── README.md ├── midgard └── test.midgard ├── src ├── assembler │ └── assembler.odin ├── constant │ └── value.odin ├── frontend │ ├── ast.odin │ ├── builtin.odin │ ├── checker.odin │ ├── decl.odin │ ├── entity.odin │ ├── errors.odin │ ├── expr.odin │ ├── parser.odin │ ├── stmt.odin │ ├── token.odin │ ├── tokenizer.odin │ ├── type_expr.odin │ └── types.odin └── main.odin ├── test.html └── test.wasm /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2020, Ginger Bill 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /Odin.cloc: -------------------------------------------------------------------------------- 1 | Odin 2 | filter remove_matches ^\s*// 3 | filter call_regexp_common C 4 | extension odin 5 | 3rd_gen_scale 1.51 6 | Badscript 7 | filter remove_matches ^\s*// 8 | filter call_regexp_common C 9 | extension bs 10 | 3rd_gen_scale 1.51 11 | Koi 12 | filter remove_matches ^\s*// 13 | filter call_regexp_common C 14 | extension koi 15 | 3rd_gen_scale 1.51 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Midgard 2 | The Midgard Programming Language - designed specifically for the WASM platform 3 | -------------------------------------------------------------------------------- /midgard/test.midgard: -------------------------------------------------------------------------------- 1 | import "foo" 2 | 3 | const A = 123 4 | var b isize = 123 5 | 6 | const ( 7 | C = 123 + 345 8 | D = 123 9 | ) 10 | const FOO = 123 11 | 12 | type ( 13 | My_Int isize 14 | Int_Alias = isize 15 | ) 16 | 17 | type My_Type struct { 18 | x i32 19 | y f32 20 | z, w, a bool 21 | } 22 | 23 | 24 | proc main() { 25 | print() 26 | print2(1234) 27 | print() 28 | print() 29 | } 30 | 31 | foreign "env" proc print() 32 | foreign "env" proc print2(x f32) 33 | // foreign "env" proc print3(i32) 34 | 35 | 36 | 37 | // proc the_thing() { 38 | // var x isize = 123 39 | // type Foo struct { 40 | // x i32 41 | // y f32 42 | // z, w, a bool 43 | // } 44 | 45 | // var cond = true 46 | 47 | // print() 48 | 49 | // if cond { 50 | // for var i = 0; i < 10; i += 1 { 51 | 52 | // } 53 | // } 54 | 55 | // proc foo() { 56 | // var cond = false 57 | // if cond { 58 | 59 | // } 60 | // } 61 | // } 62 | 63 | -------------------------------------------------------------------------------- /src/assembler/assembler.odin: -------------------------------------------------------------------------------- 1 | package wasm_assembler 2 | 3 | import "core:fmt" 4 | 5 | PAGE_SIZE :: 1<<16; 6 | 7 | Val_Type :: enum u8 { 8 | void = 0x00, 9 | i32 = 0x7f, 10 | i64 = 0x7e, 11 | f32 = 0x7d, 12 | f64 = 0x7c, 13 | } 14 | 15 | Op :: enum u16le { 16 | Unreachable = 0x00, 17 | Nop = 0x01, 18 | Block = 0x02, 19 | Loop = 0x03, 20 | If = 0x04, 21 | End = 0x0b, 22 | Br = 0x0c, 23 | Br_If = 0x0d, 24 | Br_Table = 0x0e, 25 | Return = 0x0f, 26 | Call = 0x10, 27 | Call_Indirect = 0x11, 28 | 29 | Drop = 0x1a, 30 | Select = 0x1b, 31 | 32 | Local_Get = 0x20, 33 | Local_Set = 0x21, 34 | Local_Tee = 0x22, // Sets and then returns value 35 | Global_Get = 0x23, 36 | Global_Set = 0x24, 37 | 38 | Load_i32 = 0x28, 39 | Load_i64 = 0x29, 40 | Load_f32 = 0x2a, 41 | Load_f64 = 0x2b, 42 | 43 | Load_i32_as_s8 = 0x2c, 44 | Load_i32_as_u8 = 0x2d, 45 | Load_i32_as_s16 = 0x2e, 46 | Load_i32_as_u16 = 0x2f, 47 | 48 | Load_i64_as_s8 = 0x30, 49 | Load_i64_as_u8 = 0x31, 50 | Load_i64_as_s16 = 0x32, 51 | Load_i64_as_u16 = 0x33, 52 | Load_i64_as_s32 = 0x34, 53 | Load_i64_as_u32 = 0x35, 54 | 55 | Store_i32 = 0x36, 56 | Store_i64 = 0x37, 57 | Store_f32 = 0x38, 58 | Store_f64 = 0x39, 59 | 60 | Store_i32_i8 = 0x3a, 61 | Store_i32_i16 = 0x3b, 62 | 63 | Store_i64_i8 = 0x3c, 64 | Store_i64_i16 = 0x3d, 65 | Store_i64_i32 = 0x3e, 66 | 67 | Memory_Size = 0x3f, 68 | Memory_Grow = 0x40, 69 | 70 | Const_i32 = 0x41, 71 | Const_i64 = 0x42, 72 | Const_f32 = 0x43, 73 | Const_f64 = 0x44, 74 | 75 | Eqz_i32 = 0x45, 76 | Eq_i32 = 0x46, 77 | Ne_i32 = 0x47, 78 | Lt_s32 = 0x48, 79 | Lt_u32 = 0x49, 80 | Gt_s32 = 0x4a, 81 | Gt_u32 = 0x4b, 82 | Le_s32 = 0x4c, 83 | Le_u32 = 0x4d, 84 | Ge_s32 = 0x4e, 85 | Ge_u32 = 0x4f, 86 | 87 | Eqz_i64 = 0x50, 88 | Eq_i64 = 0x51, 89 | Ne_i64 = 0x52, 90 | Lt_s64 = 0x53, 91 | Lt_u64 = 0x54, 92 | Gt_s64 = 0x55, 93 | Gt_u64 = 0x56, 94 | Le_s64 = 0x57, 95 | Le_u64 = 0x58, 96 | Ge_s64 = 0x59, 97 | Ge_u64 = 0x5a, 98 | 99 | Eq_f32 = 0x5b, 100 | Ne_f32 = 0x5c, 101 | Lt_f32 = 0x5d, 102 | Gt_f32 = 0x5e, 103 | Le_f32 = 0x5f, 104 | Ge_f32 = 0x60, 105 | 106 | Eq_f64 = 0x61, 107 | Ne_f64 = 0x62, 108 | Lt_f64 = 0x63, 109 | Gt_f64 = 0x64, 110 | Le_f64 = 0x65, 111 | Ge_f64 = 0x66, 112 | 113 | 114 | Clz_i32 = 0x67, 115 | Ctz_i32, 116 | Popcnt_i32, 117 | Add_i32, 118 | Sub_i32, 119 | Mul_i32, 120 | Div_s32, 121 | Div_u32, 122 | Rem_s32, 123 | Rem_u32, 124 | And_i32, 125 | Or_i32, 126 | Xor_i32, 127 | Shl_i32, 128 | Shr_s32, 129 | Shr_u32, 130 | Rotl_i32, 131 | Rotr_i32 = 0x78, 132 | 133 | Clz_i64 = 0x79, 134 | Ctz_i64, 135 | Popcnt_i64, 136 | Add_i64, 137 | Sub_i64, 138 | Mul_i64, 139 | Div_s64, 140 | Div_u64, 141 | Rem_s64, 142 | Rem_u64, 143 | And_i64, 144 | Or_i64, 145 | Xor_i64, 146 | Shl_i64, 147 | Shr_s64, 148 | Shr_u64, 149 | Rotl_i64, 150 | Rotr_i64 = 0x8a, 151 | 152 | Abs_f32 = 0x8b, 153 | Neg_f32, 154 | Ceil_f32, 155 | Floor_f32, 156 | Trunc_f32, 157 | Nearest_f32, 158 | Sqrt_f32, 159 | Add_f32, 160 | Sub_f32, 161 | Mul_f32, 162 | Div_f32, 163 | Min_f32, 164 | Max_f32, 165 | Copysign_f32 = 0x98, 166 | 167 | Abs_f64 = 0x99, 168 | Neg_f64, 169 | Ceil_f64, 170 | Floor_f64, 171 | Trunc_f64, 172 | Nearest_f64, 173 | Sqrt_f64, 174 | Add_f64, 175 | Sub_f64, 176 | Mul_f64, 177 | Div_f64, 178 | Min_f64, 179 | Max_f64, 180 | Copysign_f64 = 0xa6, 181 | 182 | 183 | Wrap_i64_to_i32 = 0xa7, 184 | Trunc_f32_s32, 185 | Trunc_f32_u32, 186 | Trunc_f64_s32, 187 | Trunc_f64_u32, 188 | Extend_i32_s64, 189 | Extend_i32_u64, 190 | Trunc_f32_s64, 191 | Trunc_f32_u64, 192 | Trunc_f64_s64, 193 | Trunc_f64_u64, 194 | Convert_s32_f32, 195 | Convert_u32_f32, 196 | Convert_s64_f32, 197 | Convert_u64_f32, 198 | Demote_f64_to_f32, 199 | Convert_s32_to_f64, 200 | Convert_u32_to_f64, 201 | Convert_s64_to_f64, 202 | Convert_u64_to_f64, 203 | Promote_f32_to_f64, 204 | Reinterpret_f32_to_i32, 205 | Reinterpret_f64_to_i64, 206 | Reinterpret_i32_to_f32, 207 | Reinterpret_i64_to_f64 = 0xbf, 208 | 209 | Extend_s8_to_i32 = 0xc0, 210 | Extend_s16_to_i32 = 0xc1, 211 | Extend_s8_to_i64 = 0xc2, 212 | Extend_s16_to_i64 = 0xc3, 213 | Extend_s32_to_i64 = 0xc4, 214 | 215 | GAP = 0xff, 216 | 217 | trunc_sat_f32_to_s32 = 0x00_fc, 218 | trunc_sat_f32_to_u32 = 0x01_fc, 219 | trunc_sat_f64_to_s32 = 0x02_fc, 220 | trunc_sat_f64_to_u32 = 0x03_fc, 221 | trunc_sat_f32_to_s64 = 0x04_fc, 222 | trunc_sat_f32_to_u64 = 0x05_fc, 223 | trunc_sat_f64_to_s64 = 0x06_fc, 224 | trunc_sat_f64_to_u64 = 0x07_fc, 225 | } 226 | 227 | Section :: enum u8 { 228 | Custom = 0x00, 229 | Type = 0x01, 230 | Import = 0x02, 231 | Function = 0x03, 232 | Table = 0x04, 233 | Memory = 0x05, 234 | Global = 0x06, 235 | Export = 0x07, 236 | Start = 0x08, 237 | Element = 0x09, 238 | Code = 0x0a, 239 | Data = 0x0b, 240 | } 241 | 242 | 243 | Emitter :: struct { 244 | binary_data: [dynamic]byte, 245 | } 246 | 247 | Assembler :: struct { 248 | emitter: Emitter, 249 | signatures: [dynamic]Signature, 250 | funcs: [dynamic]Function, 251 | imports: [dynamic]Import, 252 | globals: [dynamic]Global, 253 | memories: [1]Memory, 254 | memories_len: u32, 255 | func_indices: map[string]u32, 256 | global_indices: map[string]u32, 257 | 258 | data_section_size: u32, 259 | datums: [dynamic]Datum, 260 | } 261 | 262 | 263 | MAGIC := [4]byte{0x00, 0x61, 0x73, 0x6d}; 264 | VERSION := [4]byte{0x01, 0x00, 0x00, 0x00}; 265 | 266 | MAX_PARAM_LEN :: 16; 267 | 268 | Signature :: struct { 269 | index: u32, 270 | 271 | params: [MAX_PARAM_LEN]Val_Type, 272 | param_len: u8, 273 | results: [1]Val_Type, 274 | result_len: u8, 275 | } 276 | 277 | Location_Kind :: enum { 278 | Internal = 0, 279 | Export, 280 | Import, 281 | } 282 | 283 | Function :: struct { 284 | name: string, 285 | sig: ^Signature, 286 | kind: Location_Kind, 287 | code: Emitter, 288 | } 289 | 290 | Import_Kind :: enum u8 { 291 | Func = 0x00, 292 | Table = 0x01, 293 | Mem = 0x02, 294 | Global = 0x03, 295 | } 296 | 297 | Import :: struct { 298 | kind: Import_Kind, 299 | module: string, 300 | name: string, 301 | type: union{Val_Type, ^Signature}, 302 | } 303 | 304 | Global_Expr :: union { 305 | i32, i64, 306 | f32, f64, 307 | []byte, 308 | } 309 | 310 | Global :: struct { 311 | type: Val_Type, 312 | is_const: bool, 313 | expr: Global_Expr, 314 | name: string, 315 | kind: Location_Kind, 316 | } 317 | 318 | Memory :: struct { 319 | limit_min: u32, 320 | limit_max: u32, 321 | name: string, 322 | } 323 | 324 | Datum :: struct { 325 | offset: i32, 326 | memory: []byte, 327 | } 328 | 329 | EXPORT_DESC_FUNC :: 0x00; 330 | EXPORT_DESC_TABLE :: 0x01; 331 | EXPORT_DESC_MEM :: 0x02; 332 | EXPORT_DESC_GLOBAL :: 0x03; 333 | 334 | 335 | emit_header :: proc(using e: ^Emitter) { 336 | append(&binary_data, ..MAGIC[:]); 337 | append(&binary_data, ..VERSION[:]); 338 | } 339 | 340 | emit_byte :: proc(using e: ^Emitter, b: byte) { 341 | append(&binary_data, b); 342 | } 343 | 344 | emit_bytes :: proc(using e: ^Emitter, bytes: ..byte) { 345 | append(&binary_data, ..bytes); 346 | } 347 | 348 | emit_type :: proc(using e: ^Emitter, t: Val_Type) { 349 | append(&binary_data, byte(t)); 350 | } 351 | 352 | emit_op :: proc(using e: ^Emitter, op: Op) { 353 | if op <= .GAP { 354 | append(&binary_data, byte(op)); 355 | } else { 356 | data := transmute([2]u8)u16le(op); 357 | append(&binary_data, data[0], data[1]); 358 | } 359 | } 360 | 361 | u32_byte_length :: proc(u: int) -> u32 { 362 | length := u32(0); 363 | value := u32le(u); 364 | for { 365 | b := byte(value & 0x7f); 366 | value >>= 7; 367 | if value != 0 { 368 | b |= 0x80; 369 | } 370 | length += 1; 371 | if value == 0 { 372 | break; 373 | } 374 | } 375 | return length; 376 | } 377 | 378 | u32_byte_length32 :: proc(u: u32) -> u32 { 379 | length := u32(0); 380 | value := u32le(u); 381 | for { 382 | b := byte(value & 0x7f); 383 | value >>= 7; 384 | if value != 0 { 385 | b |= 0x80; 386 | } 387 | length += 1; 388 | if value == 0 { 389 | break; 390 | } 391 | } 392 | return length; 393 | } 394 | i32_byte_length32 :: proc(u: i32) -> u32 { 395 | length := u32(0); 396 | 397 | value := i32le(u); 398 | negative := value < 0; 399 | size := size_of(value)*8; 400 | 401 | more := true; 402 | for more { 403 | b := byte(value & 0x7f); 404 | value >>= 7; 405 | 406 | if negative { 407 | value |= ~i32le(0) << u32le(size - 7); 408 | } 409 | 410 | if value == 0 && (b & 0x40) != 0x40 || 411 | value == -1 && (b & 0x40) == 0x40 { 412 | more = false; 413 | } else { 414 | b |= 0x80; 415 | } 416 | length += 1; 417 | } 418 | return length; 419 | } 420 | u64_byte_length32 :: proc(u: u64) -> u32 { 421 | length := u32(0); 422 | value := u64le(u); 423 | for { 424 | b := byte(value & 0x7f); 425 | value >>= 7; 426 | if value != 0 { 427 | b |= 0x80; 428 | } 429 | length += 1; 430 | if value == 0 { 431 | break; 432 | } 433 | } 434 | return length; 435 | } 436 | i64_byte_length32 :: proc(u: i64) -> u32 { 437 | length := u32(0); 438 | 439 | value := i64le(u); 440 | negative := value < 0; 441 | size := size_of(value)*8; 442 | 443 | more := true; 444 | for more { 445 | b := byte(value & 0x7f); 446 | value >>= 7; 447 | 448 | if negative { 449 | value |= ~i64le(0) << u64le(size - 7); 450 | } 451 | 452 | if value == 0 && (b & 0x40) != 0x40 || 453 | value == -1 && (b & 0x40) == 0x40 { 454 | more = false; 455 | } else { 456 | b |= 0x80; 457 | } 458 | length += 1; 459 | } 460 | return length; 461 | } 462 | 463 | emit_u32 :: proc(using e: ^Emitter, u: u32) { 464 | value := u32le(u); 465 | for { 466 | b := byte(value & 0x7f); 467 | value >>= 7; 468 | if value != 0 { 469 | b |= 0x80; 470 | } 471 | append(&binary_data, b); 472 | if value == 0 { 473 | break; 474 | } 475 | } 476 | } 477 | emit_u64 :: proc(using e: ^Emitter, u: u64) { 478 | value := u64le(u); 479 | for { 480 | b := byte(value & 0x7f); 481 | value >>= 7; 482 | if value != 0 { 483 | b |= 0x80; 484 | } 485 | append(&binary_data, b); 486 | if value == 0 { 487 | break; 488 | } 489 | } 490 | } 491 | 492 | emit_i32 :: proc(using e: ^Emitter, u: i32) { 493 | value := i32le(u); 494 | negative := value < 0; 495 | size := size_of(value)*8; 496 | 497 | more := true; 498 | for more { 499 | b := byte(value & 0x7f); 500 | value >>= 7; 501 | 502 | if negative { 503 | value |= ~i32le(0) << u32le(size - 7); 504 | } 505 | 506 | if value == 0 && (b & 0x40) != 0x40 || 507 | value == -1 && (b & 0x40) == 0x40 { 508 | more = false; 509 | } else { 510 | b |= 0x80; 511 | } 512 | append(&binary_data, b); 513 | } 514 | } 515 | emit_i64 :: proc(using e: ^Emitter, u: i64) { 516 | value := i64le(u); 517 | negative := value < 0; 518 | size := size_of(value)*8; 519 | 520 | more := true; 521 | for more { 522 | b := byte(value & 0x7f); 523 | value >>= 7; 524 | 525 | if negative { 526 | value |= ~i64le(0) << u64le(size - 7); 527 | } 528 | 529 | if value == 0 && (b & 0x40) != 0x40 || 530 | value == -1 && (b & 0x40) == 0x40 { 531 | more = false; 532 | } else { 533 | b |= 0x80; 534 | } 535 | append(&binary_data, b); 536 | } 537 | } 538 | 539 | emit_f32 :: proc(using e: ^Emitter, f: f32) { 540 | value := transmute([4]byte)f32le(f); 541 | append(&binary_data, ..value[:]); 542 | } 543 | emit_f64 :: proc(using e: ^Emitter, f: f64) { 544 | value := transmute([8]byte)f64le(f); 545 | append(&binary_data, ..value[:]); 546 | } 547 | 548 | emit_name :: proc(using e: ^Emitter, name: string) { 549 | n := u32(len(name)); 550 | emit_u32(e, n); 551 | append(&binary_data, name); 552 | } 553 | 554 | emit_name_byte_length :: proc(name: string) -> u32 { 555 | return u32_byte_length(len(name)) + u32(len(name)); 556 | } 557 | 558 | emit_section :: proc(using e: ^Emitter, section: Section, size: u32) { 559 | append(&binary_data, byte(section)); 560 | emit_u32(e, size); 561 | } 562 | 563 | emit_call :: proc(e: ^Emitter, func_index: u32) { 564 | emit_op(e, .Call); 565 | emit_u32(e, func_index); 566 | } 567 | 568 | emit_limits_min :: proc(e: ^Emitter, min: u32) { 569 | emit_byte(e, 0x00); 570 | emit_u32(e, min); 571 | } 572 | emit_limits_min_max :: proc(e: ^Emitter, min, max: u32) { 573 | emit_byte(e, 0x01); 574 | emit_u32(e, min); 575 | emit_u32(e, max); 576 | } 577 | 578 | emit_table_type_min :: proc(e: ^Emitter, min: u32) { 579 | emit_byte(e, 0x70); 580 | emit_limits_min(e, min); 581 | } 582 | emit_table_type_min_max :: proc(e: ^Emitter, min, max: u32) { 583 | emit_byte(e, 0x70); 584 | emit_limits_min_max(e, min, max); 585 | } 586 | 587 | emit_global_type :: proc(e: ^Emitter, t: Val_Type, is_const: bool) { 588 | emit_type(e, t); 589 | emit_byte(e, 0x01 if is_const else 0x00); 590 | } 591 | 592 | emit_const_i32 :: proc(e: ^Emitter, val: i32) { 593 | emit_op(e, .Const_i32); emit_i32(e, val); 594 | } 595 | emit_const_i64 :: proc(e: ^Emitter, val: i64) { 596 | emit_op(e, .Const_i64); emit_i64(e, val); 597 | } 598 | emit_const_f32 :: proc(e: ^Emitter, val: f32) { 599 | emit_op(e, .Const_f32); emit_f32(e, val); 600 | } 601 | emit_const_f64 :: proc(e: ^Emitter, val: f64) { 602 | emit_op(e, .Const_f64); emit_f64(e, val); 603 | } 604 | 605 | emit_mem_arg :: proc(e: ^Emitter, offset, align: u32) { 606 | emit_u32(e, offset); 607 | emit_u32(e, align); 608 | } 609 | 610 | emit_load_i32 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i32le)) { 611 | emit_op(e, .Load_i32); emit_mem_arg(e, offset, align); 612 | } 613 | 614 | emit_load_i64 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i64le)) { 615 | emit_op(e, .Load_i64); emit_mem_arg(e, offset, align); 616 | } 617 | 618 | emit_load_f32 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(f32le)) { 619 | emit_op(e, .Load_f32); emit_mem_arg(e, offset, align); 620 | } 621 | 622 | emit_load_f64 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(f64le)) { 623 | emit_op(e, .Load_f64); emit_mem_arg(e, offset, align); 624 | } 625 | 626 | 627 | emit_load_i32_as_s8 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i32le)) { 628 | emit_op(e, .Load_i32_as_s8); emit_mem_arg(e, offset, align); 629 | } 630 | emit_load_i32_as_u8 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i32le)) { 631 | emit_op(e, .Load_i32_as_u8); emit_mem_arg(e, offset, align); 632 | } 633 | emit_load_i32_as_s16 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i32le)) { 634 | emit_op(e, .Load_i32_as_s16); emit_mem_arg(e, offset, align); 635 | } 636 | emit_load_i32_as_u16 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i32le)) { 637 | emit_op(e, .Load_i32_as_u16); emit_mem_arg(e, offset, align); 638 | } 639 | 640 | emit_load_i64_as_s8 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i64le)) { 641 | emit_op(e, .Load_i64_as_s8); emit_mem_arg(e, offset, align); 642 | } 643 | emit_load_i64_as_u8 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i64le)) { 644 | emit_op(e, .Load_i64_as_u8); emit_mem_arg(e, offset, align); 645 | } 646 | emit_load_i64_as_s16 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i64le)) { 647 | emit_op(e, .Load_i64_as_s16); emit_mem_arg(e, offset, align); 648 | } 649 | emit_load_i64_as_u16 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i64le)) { 650 | emit_op(e, .Load_i64_as_u16); emit_mem_arg(e, offset, align); 651 | } 652 | emit_load_i64_as_s32 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i64le)) { 653 | emit_op(e, .Load_i64_as_s32); emit_mem_arg(e, offset, align); 654 | } 655 | emit_load_i64_as_u32 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i64le)) { 656 | emit_op(e, .Load_i64_as_u32); emit_mem_arg(e, offset, align); 657 | } 658 | 659 | emit_store_i32 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i32le)) { 660 | emit_op(e, .Store_i32); emit_mem_arg(e, offset, align); 661 | } 662 | emit_store_i64 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i32le)) { 663 | emit_op(e, .Store_i64); emit_mem_arg(e, offset, align); 664 | } 665 | emit_store_f32 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i32le)) { 666 | emit_op(e, .Store_f32); emit_mem_arg(e, offset, align); 667 | } 668 | emit_store_f64 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i32le)) { 669 | emit_op(e, .Store_f64); emit_mem_arg(e, offset, align); 670 | } 671 | 672 | emit_store_i32_i8 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i32le)) { 673 | emit_op(e, .Store_i32_i8); emit_mem_arg(e, offset, align); 674 | } 675 | emit_store_i32_i16 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i32le)) { 676 | emit_op(e, .Store_i32_i16); emit_mem_arg(e, offset, align); 677 | } 678 | 679 | emit_store_i64_i8 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i32le)) { 680 | emit_op(e, .Store_i64_i8); emit_mem_arg(e, offset, align); 681 | } 682 | emit_store_i64_i16 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i32le)) { 683 | emit_op(e, .Store_i64_i16); emit_mem_arg(e, offset, align); 684 | } 685 | emit_store_i64_i32 :: proc(e: ^Emitter, offset: u32, align: u32 = align_of(i32le)) { 686 | emit_op(e, .Store_i64_i32); emit_mem_arg(e, offset, align); 687 | } 688 | 689 | 690 | signature_equal :: proc(a, b: Signature) -> bool { 691 | if a.param_len != b.param_len { 692 | return false; 693 | } 694 | if a.result_len != b.result_len { 695 | return false; 696 | } 697 | return a.params == b.params && a.results == b.results; 698 | } 699 | 700 | signature :: proc(a: ^Assembler, params: []Val_Type, result: Val_Type) -> ^Signature { 701 | assert(len(params) <= MAX_PARAM_LEN); 702 | 703 | sig: Signature; 704 | sig.param_len = min(u8(len(params)), len(sig.params)); 705 | copy(sig.params[:], params); 706 | 707 | sig.result_len = 1 if result != .void else 0; 708 | sig.results[0] = result; 709 | 710 | // TODO(bill): Hash Map Cache 711 | for signature, i in a.signatures { 712 | if signature_equal(sig, signature) { 713 | return &a.signatures[i]; 714 | } 715 | } 716 | 717 | index := u32(len(a.signatures)); 718 | sig.index = index; 719 | append(&a.signatures, sig); 720 | return &a.signatures[index]; 721 | } 722 | 723 | create_function :: proc(a: ^Assembler, def: Function) -> ^Emitter { 724 | assert(def.name not_in a.func_indices); 725 | append(&a.funcs, def); 726 | n := len(a.funcs)-1; 727 | func := &a.funcs[n]; 728 | a.func_indices[func.name] = u32(n + len(a.imports)); 729 | return &func.code; 730 | } 731 | 732 | func_index :: proc(a: ^Assembler, name: string) -> u32 { 733 | index, ok := a.func_indices[name]; 734 | assert(ok); 735 | return index; 736 | } 737 | 738 | 739 | func_sig_index :: proc(a: ^Assembler, name: string) -> u32 { 740 | index, ok := a.func_indices[name]; 741 | assert(ok); 742 | return index; 743 | } 744 | 745 | get_func :: proc(a: ^Assembler, name: string) -> ^Function { 746 | index, ok := a.func_indices[name]; 747 | assert(ok); 748 | return &a.funcs[index]; 749 | } 750 | 751 | import_function :: proc(a: ^Assembler, module, name: string, sig: ^Signature) -> u32 { 752 | assert(len(a.funcs) == 0, "imports must happen before functions are declared"); 753 | 754 | imp := Import{ 755 | kind = .Func, 756 | module = module, 757 | name = name, 758 | type = sig, 759 | }; 760 | append(&a.imports, imp); 761 | return u32(len(a.imports)-1); 762 | } 763 | 764 | add_global :: proc(a: ^Assembler, global: Global) -> u32 { 765 | n := u32(len(a.globals)); 766 | g := global; 767 | if g.type == .void { 768 | switch x in g.expr { 769 | case i32: g.type = .i32; 770 | case i64: g.type = .i64; 771 | case f32: g.type = .f32; 772 | case f64: g.type = .f64; 773 | case []byte: panic("a byte expression must specify a type"); 774 | } 775 | } 776 | if g.expr == nil { 777 | assert(g.type != .void); 778 | } 779 | if g.kind != .Internal { 780 | assert(g.name != ""); 781 | } 782 | if g.name != "" { 783 | a.global_indices[g.name] = u32(len(a.globals)); 784 | } 785 | 786 | append(&a.globals, g); 787 | return n; 788 | } 789 | 790 | add_memory :: proc(a: ^Assembler, min: u32, name: string) { 791 | assert(a.memories_len == 0); 792 | min_pages := (min + PAGE_SIZE-1)/PAGE_SIZE; 793 | 794 | a.memories[a.memories_len] = Memory{ 795 | limit_min = min_pages, 796 | limit_max = max(u32), 797 | name = name, 798 | }; 799 | 800 | a.memories_len += 1; 801 | } 802 | 803 | add_datum :: proc(a: ^Assembler, offset: i32, data: []byte) { 804 | datum := Datum { 805 | offset = offset, 806 | memory = data, 807 | }; 808 | append(&a.datums, datum); 809 | a.data_section_size += u32(len(datum.memory)); 810 | } 811 | 812 | add_datum_string :: proc(a: ^Assembler, offset: i32, str: string) { 813 | datum := Datum { 814 | offset = offset, 815 | memory = transmute([]byte)str, 816 | }; 817 | append(&a.datums, datum); 818 | a.data_section_size += u32(len(datum.memory)); 819 | } 820 | 821 | 822 | generate_assembly :: proc(using a: ^Assembler) { 823 | e := &emitter; 824 | emit_header(e); 825 | 826 | { // Type Section 827 | section_size := u32(0); 828 | section_size += u32_byte_length(len(signatures)); 829 | for sigature in signatures { 830 | section_size += 1; // func type 831 | // param vec count 832 | section_size += u32_byte_length(int(sigature.param_len)); 833 | // params 834 | section_size += u32(sigature.param_len); 835 | 836 | // result vec count 837 | section_size += u32_byte_length(int(sigature.result_len)); 838 | // results 839 | section_size += u32(sigature.result_len); 840 | } 841 | 842 | emit_section(e, .Type, section_size); 843 | emit_u32(e, u32(len(signatures))); 844 | for sig in signatures { 845 | emit_byte(e, 0x60); 846 | emit_u32(e, u32(sig.param_len)); 847 | for i in 0.. (res: Value, ok: bool) { 36 | switch v in value { 37 | case bool: 38 | return; 39 | case string: 40 | return; 41 | case i128: 42 | res = i128(v); 43 | ok = true; 44 | case f64: 45 | res = i128(v); 46 | ok = true; 47 | } 48 | 49 | return; 50 | } 51 | 52 | 53 | as_float :: proc(value: Value) -> (res: Value, ok: bool) { 54 | switch v in value { 55 | case bool: 56 | return; 57 | case string: 58 | return; 59 | case i128: 60 | res = f64(v); 61 | ok = true; 62 | case f64: 63 | res = f64(v); 64 | ok = true; 65 | } 66 | 67 | return; 68 | } 69 | 70 | 71 | as_i64 :: proc(value: Value) -> (res: i64, ok: bool) { 72 | switch v in value { 73 | case bool: 74 | return; 75 | case string: 76 | return; 77 | case i128: 78 | res = i64(v); 79 | ok = true; 80 | case f64: 81 | res = i64(v); 82 | ok = true; 83 | } 84 | 85 | return; 86 | } 87 | 88 | 89 | as_bool :: proc(value: Value) -> (res: Value, ok: bool) { 90 | #partial switch v in value { 91 | case bool: 92 | return v, true; 93 | } 94 | 95 | return; 96 | } 97 | 98 | 99 | sign :: proc(value: Value) -> int { 100 | switch v in value { 101 | case bool: 102 | return 0; 103 | case string: 104 | return 0; 105 | case i128: 106 | if v < 0 { 107 | return -1; 108 | } else if v > 0 { 109 | return +1; 110 | } 111 | case f64: 112 | if v < 0 { 113 | return -1; 114 | } else if v > 0 { 115 | return +1; 116 | } 117 | } 118 | 119 | return 0; 120 | } 121 | 122 | 123 | order :: proc(value: Value) -> int { 124 | if value == nil { 125 | return 0; 126 | } 127 | switch v in value { 128 | case bool, string: 129 | return 1; 130 | case i128: 131 | return 2; 132 | case f64: 133 | return 3; 134 | } 135 | return -1; 136 | } 137 | 138 | match :: proc(x, y: Value) -> (Value, Value) { 139 | x, y := x, y; 140 | if order(x) > order(y) { 141 | y, x = match(y, x); 142 | return x, y; 143 | } 144 | 145 | switch a in x { 146 | case bool, string: 147 | return x, y; 148 | case i128: 149 | #partial switch b in y { 150 | case i128: return x, y; 151 | case f64: return x, i128(b); 152 | } 153 | case f64: 154 | #partial switch b in y { 155 | case i128: return x, f64(b); 156 | case f64: return x, y; 157 | } 158 | } 159 | 160 | return x, x; 161 | } 162 | 163 | unary_op :: proc(op: Op, x: Value) -> Value { 164 | switch x in x { 165 | case bool: 166 | #partial switch op { 167 | case .Not: return !x; 168 | } 169 | case i128: 170 | #partial switch op { 171 | case .Xor: return ~x; 172 | } 173 | case f64: 174 | case string: 175 | } 176 | return nil; 177 | } 178 | 179 | binary_op :: proc(x_: Value, op: Op, y_: Value) -> Value { 180 | x, y := match(x_, y_); 181 | if x == nil { 182 | return x; 183 | } 184 | switch x in x { 185 | case bool: 186 | y := y.(bool); 187 | #partial switch op { 188 | case .And: return x & y; 189 | case .Or: return x | y; 190 | case .Xor: return x ~ y; 191 | case .Cmp_And: return x && y; 192 | case .Cmp_Or: return x || y; 193 | case .Cmp_Eq: return x == y; 194 | case .Not_Eq: return x != y; 195 | } 196 | case i128: 197 | y := y.(i128); 198 | #partial switch op { 199 | case .Add: return x + y; 200 | case .Sub: return x - y; 201 | case .Mul: return x * y; 202 | case .Quo: return x / y; 203 | case .Mod: return x % y; 204 | case .And: return x & y; 205 | case .Or: return x | y; 206 | case .Xor: return x ~ y; 207 | case .Shl: return x << u64(y); 208 | case .Shr: return x >> u64(y); 209 | case .And_Not: return x &~ y; 210 | case .Cmp_Eq: return x == y; 211 | case .Not_Eq: return x != y; 212 | case .Lt: return x < y; 213 | case .Gt: return x > y; 214 | case .Lt_Eq: return x <= y; 215 | case .Gt_Eq: return x >= y; 216 | } 217 | case f64: 218 | y := y.(f64); 219 | #partial switch op { 220 | case .Add: return x + y; 221 | case .Sub: return x - y; 222 | case .Mul: return x * y; 223 | case .Quo: return x / y; 224 | case .Cmp_Eq: return x == y; 225 | case .Not_Eq: return x != y; 226 | case .Lt: return x < y; 227 | case .Gt: return x > y; 228 | case .Lt_Eq: return x <= y; 229 | case .Gt_Eq: return x >= y; 230 | } 231 | case string: 232 | y := y.(string); 233 | #partial switch op { 234 | case .Cmp_Eq: return x == y; 235 | case .Not_Eq: return x != y; 236 | case .Lt: return x < y; 237 | case .Gt: return x > y; 238 | case .Lt_Eq: return x <= y; 239 | case .Gt_Eq: return x >= y; 240 | } 241 | 242 | } 243 | 244 | return x; 245 | } 246 | -------------------------------------------------------------------------------- /src/frontend/ast.odin: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | 4 | 5 | Package :: struct { 6 | id: int, 7 | name: string, 8 | fullpath: string, 9 | files: []^File, 10 | scope: ^Scope, 11 | } 12 | 13 | File :: struct { 14 | id: int, 15 | pkg: ^Package, 16 | scope: ^Scope, 17 | 18 | fullpath: string, 19 | src: []byte, 20 | 21 | decls: [dynamic]^Ast_Decl, 22 | 23 | syntax_error_count: int, 24 | } 25 | 26 | Ast_Comment_Group :: struct { 27 | list: []Token, 28 | } 29 | 30 | 31 | 32 | // Base Types 33 | Ast_Node :: struct { 34 | pos, end: Pos, // TODO(bill): should these be just procedures instead? 35 | } 36 | 37 | Ast_Expr :: struct { 38 | using node_base: Ast_Node, 39 | tav: Type_And_Value, 40 | variant: union { 41 | ^Ast_Bad_Expr, 42 | ^Ast_Ident, 43 | ^Ast_Basic_Lit, 44 | ^Ast_Unary_Expr, 45 | ^Ast_Binary_Expr, 46 | ^Ast_Paren_Expr, 47 | ^Ast_Deref_Expr, 48 | ^Ast_Call_Expr, 49 | ^Ast_Comp_Lit, 50 | ^Ast_Proc_Lit, 51 | ^Ast_Selector_Expr, 52 | ^Ast_Index_Expr, 53 | ^Ast_Slice_Expr, 54 | ^Ast_Key_Value_Expr, 55 | 56 | ^Ast_Pointer_Type, 57 | ^Ast_Array_Type, 58 | ^Ast_Struct_Type, 59 | ^Ast_Proc_Type, 60 | 61 | ^Ast_Field, 62 | ^Ast_Field_List, 63 | }, 64 | } 65 | Ast_Stmt :: struct { 66 | using node_base: Ast_Node, 67 | variant: union { 68 | ^Ast_Bad_Stmt, 69 | ^Ast_Empty_Stmt, 70 | ^Ast_Expr_Stmt, 71 | ^Ast_Decl_Stmt, 72 | ^Ast_Labeled_Stmt, 73 | ^Ast_Assign_Stmt, 74 | ^Ast_Defer_Stmt, 75 | ^Ast_Branch_Stmt, 76 | ^Ast_Block_Stmt, 77 | ^Ast_If_Stmt, 78 | ^Ast_For_Stmt, 79 | ^Ast_Switch_Stmt, 80 | ^Ast_Return_Stmt, 81 | ^Ast_Case_Clause, 82 | }, 83 | } 84 | Ast_Decl :: struct { 85 | using node_base: Ast_Node, 86 | variant: union { 87 | ^Ast_Bad_Decl, 88 | ^Ast_Gen_Decl, 89 | ^Ast_Proc_Decl, 90 | ^Ast_Foreign_Decl, 91 | }, 92 | } 93 | 94 | // Declarations 95 | 96 | Ast_Spec :: struct { 97 | using node_base: Ast_Node, 98 | variant: union { 99 | ^Ast_Import_Spec, 100 | ^Ast_Value_Spec, 101 | ^Ast_Type_Spec, 102 | ^Ast_Export_Spec, 103 | }, 104 | } 105 | 106 | 107 | Ast_Bad_Decl :: struct { 108 | using node: Ast_Decl, 109 | } 110 | 111 | Ast_Gen_Decl :: struct { 112 | using node: Ast_Decl, 113 | 114 | tok: Token, 115 | open_paren: Pos, 116 | specs: []^Ast_Spec, 117 | close_paren: Pos, 118 | } 119 | 120 | Ast_Proc_Decl :: struct { 121 | using node: Ast_Decl, 122 | name: ^Ast_Ident, 123 | type: ^Ast_Proc_Type, 124 | body: ^Ast_Block_Stmt, 125 | } 126 | 127 | Ast_Foreign_Decl :: struct { 128 | using node: Ast_Decl, 129 | tok: Token, 130 | lib: Token, 131 | open_paren: Pos, 132 | decls: []^Ast_Decl, 133 | close_paren: Pos, 134 | } 135 | 136 | Ast_Import_Spec :: struct { 137 | using node: Ast_Spec, 138 | name: ^Ast_Ident, 139 | path: ^Ast_Basic_Lit, 140 | } 141 | 142 | Ast_Value_Spec :: struct { 143 | using node: Ast_Spec, 144 | keyword: Token, 145 | names: []^Ast_Ident, 146 | type: ^Ast_Expr, 147 | values: []^Ast_Expr, 148 | } 149 | 150 | Ast_Type_Spec :: struct { 151 | using node: Ast_Spec, 152 | name: ^Ast_Ident, 153 | assign: Pos, // position of '=', if any (type alias) 154 | type: ^Ast_Expr, 155 | } 156 | 157 | Ast_Export_Spec :: struct { 158 | using node: Ast_Spec, 159 | decl: ^Ast_Decl, 160 | } 161 | 162 | 163 | 164 | // Statements 165 | 166 | Ast_Bad_Stmt :: struct { 167 | using node: Ast_Stmt, 168 | } 169 | 170 | Ast_Empty_Stmt :: struct { 171 | using node: Ast_Stmt, 172 | semicolon: Pos, // Position of the following ';' 173 | implicit: bool, 174 | } 175 | Ast_Expr_Stmt :: struct { 176 | using node: Ast_Stmt, 177 | expr: ^Ast_Expr, 178 | } 179 | Ast_Decl_Stmt :: struct { 180 | using node: Ast_Stmt, 181 | decl: ^Ast_Decl, 182 | } 183 | 184 | Ast_Labeled_Stmt :: struct { 185 | using node: Ast_Stmt, 186 | label: ^Ast_Ident, 187 | colon: Pos, 188 | stmt: ^Ast_Stmt, 189 | } 190 | 191 | 192 | Ast_Assign_Stmt :: struct { 193 | using node: Ast_Stmt, 194 | lhs: []^Ast_Expr, 195 | op: Token, 196 | rhs: []^Ast_Expr, 197 | } 198 | 199 | Ast_Block_Stmt :: struct { 200 | using node: Ast_Stmt, 201 | open: Pos, 202 | stmts: []^Ast_Stmt, 203 | close: Pos, 204 | } 205 | 206 | Ast_Defer_Stmt :: struct { 207 | using node: Ast_Stmt, 208 | tok: Token, 209 | stmt: ^Ast_Stmt, 210 | } 211 | 212 | Ast_Branch_Stmt :: struct { 213 | using node: Ast_Stmt, 214 | tok: Token, 215 | label: ^Ast_Ident, 216 | } 217 | 218 | 219 | Ast_If_Stmt :: struct { 220 | using node: Ast_Stmt, 221 | if_pos: Pos, 222 | init: ^Ast_Stmt, 223 | cond: ^Ast_Expr, 224 | body: ^Ast_Stmt, 225 | else_stmt: ^Ast_Stmt, 226 | } 227 | 228 | Ast_For_Stmt :: struct { 229 | using node: Ast_Stmt, 230 | for_pos: Pos, 231 | init: ^Ast_Stmt, 232 | cond: ^Ast_Expr, 233 | post: ^Ast_Stmt, 234 | body: ^Ast_Stmt, 235 | } 236 | 237 | Ast_Switch_Stmt :: struct { 238 | using node: Ast_Stmt, 239 | switch_pos: Pos, 240 | init: ^Ast_Stmt, 241 | cond: ^Ast_Expr, 242 | open: Pos, 243 | clauses: []^Ast_Case_Clause, 244 | close: Pos, 245 | } 246 | 247 | Ast_Case_Clause :: struct { 248 | using node: Ast_Stmt, 249 | tok: Token, 250 | clauses: []^Ast_Expr, 251 | colon: Pos, 252 | body: []^Ast_Stmt, 253 | } 254 | 255 | 256 | 257 | Ast_Return_Stmt :: struct { 258 | using node: Ast_Stmt, 259 | tok_pos: Pos, 260 | results: []^Ast_Expr, 261 | } 262 | 263 | 264 | // Expressions 265 | 266 | Ast_Bad_Expr :: struct { 267 | using node: Ast_Expr, 268 | } 269 | 270 | Ast_Ident :: struct { 271 | using node: Ast_Expr, 272 | name: string, 273 | entity: ^Entity, 274 | } 275 | 276 | Ast_Basic_Lit :: struct { 277 | using node: Ast_Expr, 278 | tok: Token, 279 | } 280 | 281 | Ast_Unary_Expr :: struct { 282 | using node: Ast_Expr, 283 | op: Token, 284 | expr: ^Ast_Expr, 285 | } 286 | 287 | Ast_Binary_Expr :: struct { 288 | using node: Ast_Expr, 289 | left: ^Ast_Expr, 290 | op: Token, 291 | right: ^Ast_Expr, 292 | } 293 | 294 | Ast_Paren_Expr :: struct { 295 | using node: Ast_Expr, 296 | open: Pos, 297 | expr: ^Ast_Expr, 298 | close: Pos, 299 | } 300 | 301 | Ast_Deref_Expr :: struct { 302 | using node: Ast_Expr, 303 | expr: ^Ast_Expr, 304 | op: Pos, 305 | } 306 | 307 | Ast_Call_Expr :: struct { 308 | using node: Ast_Expr, 309 | expr: ^Ast_Expr, 310 | open: Pos, 311 | args: []^Ast_Expr, 312 | close: Pos, 313 | } 314 | 315 | Ast_Comp_Lit :: struct { 316 | using node: Ast_Expr, 317 | type: ^Ast_Expr, 318 | open: Pos, 319 | elems: []^Ast_Expr, 320 | close: Pos, 321 | } 322 | 323 | Ast_Proc_Lit :: struct { 324 | using node: Ast_Expr, 325 | type: ^Ast_Proc_Type, 326 | body: ^Ast_Block_Stmt, 327 | } 328 | 329 | Ast_Selector_Expr :: struct { 330 | using node: Ast_Expr, 331 | x: ^Ast_Expr, 332 | sel: ^Ast_Ident, 333 | } 334 | 335 | Ast_Index_Expr :: struct { 336 | using node: Ast_Expr, 337 | x: ^Ast_Expr, 338 | open: Pos, 339 | index: ^Ast_Expr, 340 | close: Pos, 341 | } 342 | 343 | Ast_Slice_Expr :: struct { 344 | using node: Ast_Expr, 345 | x: ^Ast_Expr, 346 | open: Pos, 347 | low: ^Ast_Expr, 348 | high: ^Ast_Expr, 349 | close: Pos, 350 | } 351 | 352 | 353 | Ast_Key_Value_Expr :: struct { 354 | using node: Ast_Expr, 355 | key: ^Ast_Expr, 356 | assign: Pos, 357 | value: ^Ast_Expr, 358 | } 359 | 360 | // Field 361 | 362 | Ast_Field :: struct { 363 | using node: Ast_Expr, 364 | names: []^Ast_Ident, 365 | type: ^Ast_Expr, 366 | implicit: ^Entity, 367 | } 368 | 369 | Ast_Field_List :: struct { 370 | using node: Ast_Expr, 371 | open: Pos, 372 | list: []^Ast_Field, 373 | close: Pos, 374 | } 375 | 376 | field_count :: proc(f: ^Ast_Field_List) -> int { 377 | n := 0; 378 | if f != nil { 379 | for field in f.list { 380 | m := len(field.names); 381 | if m == 0 { 382 | m = 1; 383 | } 384 | n += m; 385 | } 386 | } 387 | return n; 388 | } 389 | 390 | 391 | // Types 392 | 393 | Ast_Pointer_Type :: struct { 394 | using node: Ast_Expr, 395 | tok: Token, 396 | elem: ^Ast_Expr, 397 | } 398 | Ast_Array_Type :: struct { 399 | using node: Ast_Expr, 400 | open: Pos, 401 | len: ^Ast_Expr, 402 | close: Pos, 403 | elem: ^Ast_Expr, 404 | } 405 | 406 | Ast_Struct_Type :: struct { 407 | using node: Ast_Expr, 408 | tok: Token, 409 | fields: ^Ast_Field_List, 410 | } 411 | 412 | 413 | Ast_Proc_Type :: struct { 414 | using node: Ast_Expr, 415 | tok: Token, 416 | params: ^Ast_Field_List, 417 | results: ^Ast_Field_List, 418 | scope: ^Scope, 419 | } 420 | 421 | -------------------------------------------------------------------------------- /src/frontend/builtin.odin: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | Builtin_Id :: enum u16 { 4 | Invalid, 5 | 6 | Len, 7 | Size_Of, 8 | Align_Of, 9 | Offset_Of, 10 | } 11 | 12 | Builtin_Proc :: struct { 13 | name: string, 14 | } 15 | 16 | builtin_procs := [Builtin_Id]Builtin_Proc{ 17 | .Invalid = {"invalid"}, 18 | 19 | .Len = {"len"}, 20 | .Size_Of = {"size_of"}, 21 | .Align_Of = {"align_of"}, 22 | .Offset_Of = {"offset_of"}, 23 | }; 24 | -------------------------------------------------------------------------------- /src/frontend/checker.odin: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import "intrinsics" 4 | import "core:fmt" 5 | import "core:strings" 6 | import "core:thread" 7 | import "../constant" 8 | 9 | universal_scope: ^Scope; 10 | universal_pkg: ^Package; 11 | 12 | 13 | Checker :: struct { 14 | pkgs: []^Package, 15 | 16 | entities: [dynamic]^Entity, 17 | 18 | builtin_pkg: ^Package, 19 | init_scope: ^Scope, 20 | 21 | task_pool: thread.Pool, 22 | procs_to_check: [dynamic]Proc_Info, 23 | 24 | err: Error_Handler, 25 | } 26 | 27 | Proc_Info :: struct { 28 | entity: ^Procedure, 29 | decl: ^Decl_Info, 30 | type: ^Signature, 31 | body: ^Ast_Block_Stmt, 32 | } 33 | 34 | 35 | Entity_Path :: struct { 36 | parent: ^Entity_Path, 37 | path: [dynamic]^Entity, // TODO(bill): Should this be a linked list with a custom allocator? 38 | } 39 | 40 | Checker_Context :: struct { 41 | checker: ^Checker, 42 | 43 | pkg: ^Package, 44 | file: ^File, 45 | scope: ^Scope, 46 | decl: ^Decl_Info, 47 | 48 | foreign_library: string, 49 | 50 | proc_name: string, 51 | curr_proc_decl: ^Decl_Info, 52 | curr_proc_type: ^Signature, 53 | 54 | entity_path: ^Entity_Path, 55 | } 56 | 57 | Addressing_Mode :: enum u8 { 58 | Invalid, 59 | No_Value, 60 | Value, 61 | Variable, 62 | Constant, 63 | Type, 64 | Builtin, 65 | } 66 | 67 | addressing_mode_strings := [Addressing_Mode]string { 68 | .Invalid = "invalid", 69 | .No_Value = "no value", 70 | .Value = "value", 71 | .Variable = "variable", 72 | .Constant = "constant", 73 | .Type = "type", 74 | .Builtin = "builtin", 75 | }; 76 | 77 | Type_And_Value :: struct { 78 | mode: Addressing_Mode, 79 | type: ^Type, 80 | value: constant.Value 81 | } 82 | 83 | Operand :: struct { 84 | using tav: Type_And_Value, 85 | expr: ^Ast_Expr, 86 | builtin_id: Builtin_Id, 87 | } 88 | 89 | SIZES := Standard_Sizes{ 90 | word_size = 4, 91 | max_align = 8, 92 | }; 93 | 94 | is_operand_nil :: proc(x: ^Operand) -> bool { 95 | return x.type == &btype[.untyped_nil]; 96 | } 97 | 98 | 99 | push_entity_path :: proc(c: ^Checker_Context) { 100 | path := new(Entity_Path); 101 | if c.entity_path != nil { 102 | c.entity_path.parent = path; 103 | } 104 | c.entity_path = path; 105 | } 106 | pop_entity_path :: proc(c: ^Checker_Context) { 107 | assert(c.entity_path != nil); 108 | parent := c.entity_path.parent; 109 | delete(c.entity_path.path); 110 | free(c.entity_path); 111 | c.entity_path = parent; 112 | } 113 | 114 | 115 | operand_set_constant :: proc(x: ^Operand, tok: Token) { 116 | kind: Basic_Kind; 117 | #partial switch tok.kind { 118 | case .Integer: 119 | kind = .untyped_int; 120 | case .Float: 121 | kind = .untyped_float; 122 | case .Rune: 123 | kind = .untyped_rune; 124 | case .String: 125 | kind = .untyped_string; 126 | case: 127 | unreachable(); 128 | } 129 | 130 | x.mode = .Constant; 131 | x.type = &btype[kind]; 132 | x.value = constant_from_token(tok); 133 | } 134 | 135 | init_universal :: proc(c: ^Checker) { 136 | universal_scope = create_scope(nil, {}, {}); 137 | universal_pkg = new(Package); 138 | universal_pkg.scope = universal_scope; 139 | universal_pkg.name = "builtin"; 140 | 141 | for _, i in btype { 142 | bt := &btype[i]; 143 | bt.variant = bt; // Initialize its variant here 144 | if strings.contains(bt.name, " ") { 145 | continue; 146 | } 147 | 148 | tname := new_type_name({}, universal_pkg, bt.name, bt); 149 | scope_insert(universal_scope, tname); 150 | } 151 | _, e_u8 := scope_lookup(universal_scope, "u8"); 152 | scope_insert_with_name(universal_scope, e_u8, "byte"); 153 | 154 | scope_insert(universal_scope, new_constant({}, universal_pkg, "false", &btype[.untyped_bool], false)); 155 | scope_insert(universal_scope, new_constant({}, universal_pkg, "true", &btype[.untyped_bool], true)); 156 | scope_insert(universal_scope, new_nil_entity({}, universal_pkg, "nil")); 157 | } 158 | 159 | 160 | check_pkgs :: proc(c: ^Checker, pkgs: []^Package) { 161 | init_universal(c); 162 | 163 | for pkg in pkgs { 164 | pkg.scope = create_scope(universal_scope, {}, {}); 165 | pkg.scope.kind = .Package; 166 | pkg.scope.pkg = pkg; 167 | for file in pkg.files { 168 | pos, end: Pos; 169 | file.scope = create_scope(pkg.scope, pos, end); 170 | file.scope.kind = .File; 171 | file.scope.pkg = pkg; 172 | file.scope.file = file; 173 | } 174 | // TODO(bill): Fix this logic 175 | if c.init_scope == nil { 176 | c.init_scope = pkg.scope; 177 | } 178 | } 179 | 180 | thread.pool_init(&c.task_pool, 1); 181 | defer thread.pool_destroy(&c.task_pool); 182 | 183 | // collect entities 184 | for pkg in pkgs { 185 | ctx := Checker_Context{}; 186 | ctx.checker = c; 187 | ctx.pkg = pkg; 188 | 189 | for file in pkg.files { 190 | ctx.file = file; 191 | ctx.scope = file.scope; 192 | collect_entities(&ctx, file.decls[:]); 193 | } 194 | } 195 | 196 | { // check package entities 197 | alias_list: [dynamic]^Type_Name; 198 | defer delete(alias_list); 199 | for e in c.entities { 200 | if tn, _ := e.variant.(^Type_Name); tn != nil && e.decl != nil && e.decl.is_alias { 201 | append(&alias_list, tn); 202 | continue; 203 | } 204 | 205 | ctx := Checker_Context{ 206 | checker = c, 207 | pkg = e.pkg, 208 | scope = e.scope, 209 | }; 210 | push_entity_path(&ctx); 211 | defer pop_entity_path(&ctx); 212 | 213 | check_entity_decl(&ctx, e, nil); 214 | } 215 | 216 | // NOTE(bill): Handle aliases after other declarations 217 | for e in alias_list { 218 | ctx := Checker_Context{ 219 | checker = c, 220 | pkg = e.pkg, 221 | scope = e.scope, 222 | }; 223 | push_entity_path(&ctx); 224 | defer pop_entity_path(&ctx); 225 | 226 | check_entity_decl(&ctx, e, nil); 227 | } 228 | 229 | } 230 | 231 | { // Check Procedure bodies 232 | for _, i in c.procs_to_check { 233 | thread.pool_add_task(&c.task_pool, proc(task: ^thread.Task) { 234 | c := (^Checker)(task.data); 235 | info := c.procs_to_check[task.user_index]; 236 | e := info.entity; 237 | d := info.decl; 238 | ctx := &Checker_Context{ 239 | checker = c, 240 | pkg = e.pkg, 241 | decl = d, 242 | scope = info.type.scope, 243 | }; 244 | check_proc_body(ctx, e, d); 245 | }, c, i); 246 | } 247 | 248 | thread.pool_start(&c.task_pool); 249 | thread.pool_wait_and_process(&c.task_pool); 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /src/frontend/decl.odin: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import "core:fmt" 4 | import "core:strings" 5 | import "core:strconv" 6 | 7 | Scope_Kind :: enum { 8 | Normal, 9 | Package, 10 | File, 11 | Type, 12 | Procedure, 13 | } 14 | Scope :: struct { 15 | parent: ^Scope, 16 | prev, next: ^Scope, 17 | first_child, last_child: ^Scope, 18 | elems: map[string]^Entity, 19 | 20 | pos: Pos, 21 | end: Pos, 22 | 23 | kind: Scope_Kind, 24 | pkg: ^Package, 25 | file: ^File, 26 | comment: string, 27 | 28 | delayed: [dynamic]^Entity, 29 | } 30 | 31 | 32 | Decl_Info :: struct { 33 | parent: ^Decl_Info, 34 | 35 | lhs: []^Variable, 36 | scope: ^Scope, 37 | 38 | type_expr: ^Ast_Expr, 39 | init_expr: ^Ast_Expr, 40 | proc_decl: ^Ast_Proc_Decl, 41 | is_alias: bool, 42 | 43 | deps: map[^Entity]bool, 44 | } 45 | 46 | create_scope :: proc(parent: ^Scope, pos, end: Pos, comment: string = "") -> ^Scope { 47 | s := new_clone(Scope{ 48 | parent = parent, 49 | comment = comment, 50 | pos = pos, 51 | end = end, 52 | }); 53 | 54 | if parent != nil && parent != universal_scope { 55 | if parent.first_child == nil { 56 | parent.first_child = s; 57 | parent.last_child = s; 58 | } else { 59 | s.prev = parent.last_child; 60 | parent.last_child.next = s; 61 | parent.last_child = s; 62 | } 63 | } 64 | return s; 65 | } 66 | 67 | scope_insert :: proc(s: ^Scope, e: ^Entity) -> ^Entity { 68 | return scope_insert_with_name(s, e, e.name); 69 | } 70 | 71 | scope_insert_with_name :: proc(s: ^Scope, e: ^Entity, name: string) -> ^Entity { 72 | if s == nil || e == nil { 73 | return nil; 74 | } 75 | if name == "" { 76 | return nil; 77 | } 78 | found := s.elems[name]; 79 | if found != nil { 80 | return found; 81 | } 82 | 83 | s.elems[name] = e; 84 | if e.scope == nil { 85 | e.scope = s; 86 | } 87 | return nil; 88 | } 89 | 90 | scope_lookup_current :: proc(s: ^Scope, name: string) -> ^Entity { 91 | if name == "" || name == "_" { 92 | return nil; 93 | } 94 | return s.elems[name]; 95 | } 96 | 97 | scope_lookup :: proc(scope: ^Scope, name: string) -> (found_scope: ^Scope, found_entity: ^Entity) { 98 | gone_thru_boundary := false; 99 | 100 | for s := scope; s != nil; s = s.parent { 101 | if e := s.elems[name]; e != nil { 102 | if gone_thru_boundary { 103 | if _, is_var := e.variant.(^Variable); is_var && (e.scope.kind != .File && e.scope.kind != .Package) { 104 | continue; 105 | } 106 | } 107 | 108 | found_scope = s; 109 | found_entity = e; 110 | return; 111 | } 112 | 113 | if s.kind == .Procedure { 114 | gone_thru_boundary = true; 115 | } 116 | if s.kind == .Package { 117 | gone_thru_boundary = true; 118 | } 119 | } 120 | return; 121 | } 122 | 123 | 124 | add_decl_dep :: proc(c: ^Checker_Context, to: ^Entity) { 125 | from := c.decl; 126 | if from == nil { 127 | return; 128 | } 129 | if to != nil { 130 | if found := to.decl; found != nil { 131 | from.deps[to] = true; 132 | } 133 | } 134 | } 135 | 136 | report_prev_decl :: proc(c: ^Checker_Context, prev: ^Entity) { 137 | assert(prev != nil); 138 | if prev.pos.line > 0 { 139 | check_error(prev.pos, " other declaration of %s", prev.name); 140 | } 141 | } 142 | 143 | declare_entity :: proc(c: ^Checker_Context, scope: ^Scope, ident: ^Ast_Ident, e: ^Entity) { 144 | assert(e != nil); 145 | e.ident = ident; 146 | e.pos = ident.pos; 147 | ident.entity = e; 148 | e.foreign_library = c.foreign_library; 149 | 150 | if e.name != "_" { 151 | if prev := scope_insert(scope, e); prev != nil { 152 | check_error(e.pos, "{} redeclared in this block", e.name); 153 | report_prev_decl(c, prev); 154 | } 155 | } 156 | } 157 | 158 | declare_pkg_entity :: proc(c: ^Checker_Context, ident: ^Ast_Ident, e: ^Entity, d: ^Decl_Info) { 159 | assert(e != nil); 160 | assert(ident.name == e.name); 161 | e.decl = d; 162 | 163 | append(&c.checker.entities, e); 164 | 165 | declare_entity(c, c.pkg.scope, ident, e); 166 | } 167 | 168 | check_arity_match :: proc(c: ^Checker_Context, s: ^Ast_Value_Spec) { 169 | l := len(s.names); 170 | r := len(s.values); 171 | 172 | switch { 173 | case r == 0: 174 | if s.type == nil { 175 | check_error(s.pos, "missing type or initial expression"); 176 | } else if s.keyword.kind == .Const { 177 | check_error(s.pos, "missing initial expression"); 178 | } 179 | case l < r: 180 | if l < len(s.values) { 181 | n := s.values[l]; 182 | check_error(n.pos, "extra initial expression"); 183 | } else { 184 | check_error(s.pos, "extra initial expression"); 185 | } 186 | case l > r && r != 1: 187 | n := s.names[r]; 188 | check_error(n.pos, "missing initial expression for {}", n.name); 189 | } 190 | } 191 | 192 | collect_entities :: proc(c: ^Checker_Context, decls: []^Ast_Decl) { 193 | for decl in decls { 194 | switch d in decl.variant { 195 | case ^Ast_Bad_Decl: 196 | // Ignore 197 | 198 | case ^Ast_Gen_Decl: 199 | for spec in d.specs { 200 | switch s in spec.variant { 201 | case ^Ast_Import_Spec: 202 | 203 | 204 | case ^Ast_Value_Spec: 205 | #partial switch s.keyword.kind { 206 | case .Const: 207 | for name, i in s.names { 208 | e := new_constant(name.pos, c.pkg, name.name, nil, i128(0)); 209 | 210 | init: ^Ast_Expr = nil; 211 | if i < len(s.values) { 212 | init = s.values[i]; 213 | } 214 | 215 | d := new_clone(Decl_Info{ 216 | scope = c.file.scope, 217 | type_expr = s.type, 218 | init_expr = init, 219 | }); 220 | declare_pkg_entity(c, name, e, d); 221 | } 222 | 223 | check_arity_match(c, s); 224 | 225 | case .Var: 226 | lhs := make([]^Variable, len(s.names)); 227 | 228 | d1: ^Decl_Info = nil; 229 | if len(s.values) == 1 { 230 | d1 = new_clone(Decl_Info{ 231 | scope = c.file.scope, 232 | lhs = lhs, 233 | type_expr = s.type, 234 | init_expr = s.values[0], 235 | }); 236 | } 237 | 238 | for name, i in s.names { 239 | e := new_variable(name.pos, c.pkg, name.name, nil); 240 | lhs[i] = e; 241 | 242 | d := d1; 243 | if d == nil { 244 | init: ^Ast_Expr; 245 | if i < len(s.values) { 246 | init = s.values[i]; 247 | } 248 | d = new_clone(Decl_Info{ 249 | scope = c.file.scope, 250 | type_expr = s.type, 251 | init_expr = init, 252 | }); 253 | } 254 | 255 | declare_pkg_entity(c, name, e, d); 256 | } 257 | 258 | check_arity_match(c, s); 259 | 260 | case: 261 | check_error(decl.pos, "invalid token: {}", s.keyword.kind); 262 | } 263 | 264 | case ^Ast_Type_Spec: 265 | e := new_type_name(s.name.pos, c.pkg, s.name.name, nil); 266 | declare_pkg_entity(c, s.name, e, new_clone(Decl_Info{ 267 | scope = c.file.scope, 268 | type_expr = s.type, 269 | is_alias = pos_is_valid(s.assign), 270 | })); 271 | 272 | case ^Ast_Export_Spec: 273 | // TODO 274 | } 275 | } 276 | 277 | case ^Ast_Proc_Decl: 278 | name := d.name.name; 279 | e := new_procedure(d.name.pos, c.pkg, name, nil); 280 | declare_entity(c, c.pkg.scope, d.name, e); 281 | e.decl = new_clone(Decl_Info{ 282 | scope = c.file.scope, 283 | proc_decl = d, 284 | }); 285 | append(&c.checker.entities, e); 286 | 287 | case ^Ast_Foreign_Decl: 288 | lib, allocated, ok := strconv.unquote_string(d.lib.text[1:len(d.lib.text)-1]); 289 | if !ok || lib == "" { 290 | check_error(d.tok.pos, "invalid foreign library string"); 291 | if allocated { 292 | delete(lib); 293 | } 294 | lib = ""; 295 | } 296 | 297 | prev_foreign_library := c.foreign_library; 298 | defer c.foreign_library = prev_foreign_library; 299 | c.foreign_library = lib; 300 | collect_entities(c, d.decls); 301 | 302 | case: 303 | check_error(decl.pos, "invalid AST, unknown Ast_Decl {:T}", d); 304 | } 305 | } 306 | 307 | for scope := c.pkg.scope.first_child; scope != nil; scope = scope.next { 308 | for name, e in scope.elems { 309 | if prev := scope_lookup_current(c.pkg.scope, e.name); prev != nil { 310 | check_error(e.pos, "{} redeclared in this package", e.name); 311 | report_prev_decl(c, prev); 312 | } 313 | } 314 | } 315 | } 316 | 317 | check_push_entity :: proc(c: ^Checker_Context, e: ^Entity) -> int { 318 | assert(e != nil); 319 | append(&c.entity_path.path, e); 320 | return len(c.entity_path.path)-1; 321 | } 322 | check_pop_entity :: proc(c: ^Checker_Context, loc := #caller_location) -> ^Entity { 323 | assert(condition=len(c.entity_path.path) > 0, loc=loc); 324 | e := pop(&c.entity_path.path); 325 | return e; 326 | } 327 | 328 | check_cycle_error :: proc(c: ^Checker_Context, cycle: []^Entity) { 329 | i := 0; 330 | e := cycle[i]; 331 | check_error(e.pos, "illegal cycle in declaration of {}", e.name); 332 | for _ in cycle { 333 | check_error(e.pos, " {} refers to", e.name); 334 | i += 1; 335 | if i >= len(cycle) { 336 | i = 0; 337 | } 338 | e = cycle[i]; 339 | } 340 | check_error(e.pos, " {}", e.name); 341 | } 342 | 343 | check_cycle :: proc(c: ^Checker_Context, entity: ^Entity) -> bool { 344 | if entity.colour < Entity_Colour_Grey { 345 | return false; 346 | } 347 | assert(entity.colour >= Entity_Colour_Grey); 348 | start := entity.colour - Entity_Colour_Grey; 349 | cycle := c.entity_path.path[start:]; 350 | val_count := 0; 351 | def_count := 0; 352 | 353 | for e in cycle { 354 | assert(e != nil); 355 | switch e in e.variant { 356 | case ^Constant, ^Variable: 357 | val_count += 1; 358 | 359 | case ^Type_Name: 360 | def_count += 1; 361 | 362 | case ^Procedure: 363 | // Ignore 364 | 365 | case ^Import_Name, ^Builtin, ^Nil: 366 | unreachable(); 367 | case: 368 | unreachable(); 369 | } 370 | } 371 | 372 | if val_count == 0 && def_count == 0 { 373 | return false; 374 | } 375 | 376 | check_cycle_error(c, cycle); 377 | 378 | return false; 379 | } 380 | 381 | 382 | check_entity_decl :: proc(c: ^Checker_Context, entity: ^Entity, def: ^Named) { 383 | // entity_path_string :: proc(path: ^Entity_Path, allocator := context.temp_allocator) -> string { 384 | // b := strings.make_builder(allocator); 385 | // strings.write_byte(&b, '['); 386 | // for p, i in path.path { 387 | // if i > 0 { 388 | // strings.write_string(&b, "->"); 389 | // } 390 | // strings.write_string(&b, p.name); 391 | // } 392 | // strings.write_byte(&b, ']'); 393 | 394 | // return strings.to_string(b); 395 | // } 396 | // check_error({}, "-- checking {} ({}, path = {})", entity.name, entity.colour, entity_path_string(c.entity_path)); 397 | // defer check_error({}, "=> {} ({})", entity.name, entity.colour); 398 | 399 | assert(entity != nil); 400 | 401 | // NOTE(bill): Three possible states: 402 | // - Type unknown yet (white) 403 | // - Type in the process of being inferred (grey) 404 | // - Type fully inferred (black) 405 | 406 | // NOTE(bill): If an entity has been assigned a type, it means it is defined 407 | // and update the colour to black 408 | if entity.colour == Entity_Colour_White && entity.type != nil { 409 | entity.colour = Entity_Colour_Black; 410 | return; 411 | } 412 | 413 | set_to_black := false; 414 | defer if set_to_black { 415 | e := check_pop_entity(c); 416 | if e != nil { 417 | assert(e != nil); 418 | entity.colour = Entity_Colour_Black; 419 | } 420 | } 421 | 422 | switch entity.colour { 423 | case Entity_Colour_White: 424 | assert(entity.type == nil); 425 | idx := check_push_entity(c, entity); 426 | entity.colour = Entity_Colour_Grey + Entity_Colour(idx); 427 | set_to_black = true; 428 | 429 | case Entity_Colour_Black: 430 | assert(entity.type != nil); 431 | return; 432 | 433 | case: fallthrough; // Anything not White or Black is Grey (infinite shades of Grey) 434 | case Entity_Colour_Grey: 435 | // CYCLE! 436 | switch e in entity.variant { 437 | case ^Constant: 438 | if check_cycle(c, e) || e.type == nil { 439 | e.type = &btype[.invalid]; 440 | } 441 | case ^Variable: 442 | if check_cycle(c, e) || e.type == nil { 443 | e.type = &btype[.invalid]; 444 | } 445 | case ^Type_Name: 446 | if check_cycle(c, e) { 447 | // NOTE(bill): Stop the cycle 448 | e.type = &btype[.invalid]; 449 | } 450 | case ^Procedure: 451 | if check_cycle(c, e) { 452 | // NOTE(bill): Don't set 453 | } 454 | case ^Import_Name, ^Builtin, ^Nil: 455 | unreachable(); 456 | case: 457 | unreachable(); 458 | } 459 | return; 460 | } 461 | d := entity.decl; 462 | if d == nil { 463 | check_error(entity.pos, "{} should be declared!", entity.name); 464 | unreachable(); 465 | } 466 | 467 | ctx := c^; 468 | ctx.scope = d.scope; 469 | 470 | switch e in entity.variant { 471 | case ^Constant: 472 | check_constant_decl(&ctx, e, d.type_expr, d.init_expr); 473 | case ^Variable: 474 | check_variable_decl(&ctx, e, d.lhs, d.type_expr, d.init_expr); 475 | case ^Type_Name: 476 | check_type_decl(&ctx, e, d.type_expr, def, d.is_alias); 477 | case ^Procedure: 478 | check_procedure_decl(&ctx, e, d); 479 | 480 | case ^Import_Name, ^Builtin, ^Nil: 481 | unreachable(); 482 | case: 483 | unreachable(); 484 | } 485 | } 486 | 487 | 488 | check_init_constant :: proc(c: ^Checker_Context, lhs: ^Constant, x: ^Operand) { 489 | if x.mode == .Invalid || x.type == &btype[.invalid] || lhs.type == &btype[.invalid] { 490 | if lhs.type == nil { 491 | lhs.type = &btype[.invalid]; 492 | } 493 | return; 494 | } 495 | 496 | if x.mode != .Constant { 497 | check_error(x.expr.pos, "{} is not a constant", x); 498 | if lhs.type == nil { 499 | lhs.type = &btype[.invalid]; 500 | } 501 | return; 502 | } 503 | 504 | if lhs.type == nil { 505 | lhs.type = x.type; 506 | } 507 | 508 | check_assignment(c, x, lhs.type, "constant declaration"); 509 | if x.mode == .Invalid { 510 | return; 511 | } 512 | lhs.value = x.value; 513 | } 514 | 515 | check_constant_decl :: proc(c: ^Checker_Context, e: ^Constant, type, init: ^Ast_Expr) { 516 | assert(e.type == nil); 517 | e.value = nil; 518 | 519 | if type != nil { 520 | t := check_type(c, type); 521 | if !is_const_type(t) { 522 | check_error(type.pos, "invalid constant type"); 523 | e.type = &btype[.invalid]; 524 | return; 525 | } 526 | e.type = t; 527 | } 528 | x: Operand; 529 | if init != nil { 530 | check_expr(c, &x, init); 531 | } 532 | check_init_constant(c, e, &x); 533 | } 534 | check_variable_decl :: proc(c: ^Checker_Context, e: ^Variable, lhs: []^Variable, type_expr, init: ^Ast_Expr) { 535 | if type_expr != nil { 536 | e.type = check_type(c, type_expr); 537 | } 538 | 539 | if init == nil { 540 | if type_expr == nil { 541 | e.type = &btype[.invalid]; 542 | } 543 | return; 544 | } 545 | 546 | if lhs == nil || len(lhs) == 1 { 547 | assert(lhs == nil || lhs[0] == e); 548 | x: Operand; 549 | check_expr(c, &x, init); 550 | check_init_variable(c, e, &x, "variable declaration"); 551 | return; 552 | } 553 | 554 | if type_expr != nil { 555 | for a in lhs { 556 | a.type = e.type; 557 | } 558 | } 559 | 560 | check_init_variables(c, lhs, {init}, {}); 561 | } 562 | 563 | check_init_variable :: proc(c: ^Checker_Context, lhs: ^Variable, x: ^Operand, ctx: string) -> ^Type { 564 | if x.mode == .Invalid || x.type == &btype[.invalid] || lhs.type == &btype[.invalid] { 565 | if lhs.type == nil { 566 | lhs.type = &btype[.invalid]; 567 | } 568 | return nil; 569 | } 570 | 571 | if lhs.type == nil { 572 | type := x.type; 573 | if type_is_untyped(type) { 574 | if type == &btype[.untyped_nil] { 575 | check_error(x.expr.pos, "use of untyped nil in {}", ctx); 576 | lhs.type = &btype[.invalid]; 577 | return nil; 578 | } 579 | // type = default_type(type); 580 | } 581 | lhs.type = type; 582 | } 583 | 584 | check_assignment(c, x, lhs.type, ctx); 585 | if x.mode == .Invalid { 586 | return nil; 587 | } 588 | 589 | return x.type; 590 | } 591 | 592 | check_init_variables :: proc(c: ^Checker_Context, lhs: []^Variable, inits: []^Ast_Expr, pos: Pos) { 593 | // TODO(bill): check_init_variables 594 | // Tuple unpacking logic 595 | } 596 | 597 | check_type_decl :: proc(c: ^Checker_Context, e: ^Type_Name, type_expr: ^Ast_Expr, def: ^Named, is_alias: bool) { 598 | assert(e.type == nil); 599 | 600 | defer check_valid_type(c, e.type, nil); 601 | 602 | if is_alias { 603 | e.type = &btype[.invalid]; 604 | e.type = check_type(c, type_expr); 605 | } else { 606 | named := new(Named); 607 | set_underlying(def, named); 608 | e.type = named; 609 | named.original = check_type(c, type_expr, named); 610 | named.underlying = type_underlying(named); 611 | } 612 | } 613 | check_procedure_decl :: proc(c: ^Checker_Context, e: ^Procedure, d: ^Decl_Info) { 614 | assert(e.type == nil); 615 | 616 | sig := new_type(Signature); 617 | e.type = sig; 618 | proc_decl := d.proc_decl; 619 | check_proc_type(c, sig, proc_decl.type); 620 | 621 | if proc_decl.body != nil && (c.scope.kind != .Type && c.scope.kind != .Procedure) { 622 | info := Proc_Info{ 623 | decl = d, 624 | type = sig, 625 | body = proc_decl.body, 626 | entity = e, 627 | }; 628 | append(&c.checker.procs_to_check, info); 629 | } 630 | } 631 | 632 | check_proc_body :: proc(c: ^Checker_Context, e: ^Procedure, d: ^Decl_Info) { 633 | push_entity_path(c); 634 | defer pop_entity_path(c); 635 | 636 | check_stmt_list(c, nil, d.proc_decl.body.stmts); 637 | } 638 | 639 | 640 | 641 | 642 | check_valid_type :: proc(c: ^Checker_Context, type: ^Type, path: ^[dynamic]^Entity) -> Named_State { 643 | #partial switch t in type.variant { 644 | case ^Array: 645 | return check_valid_type(c, t.elem, path); 646 | case ^Struct: 647 | for f in t.fields { 648 | if check_valid_type(c, f.type, path) == .Invalid { 649 | return .Invalid; 650 | } 651 | } 652 | case ^Tuple: 653 | for v in t.vars { 654 | if check_valid_type(c, v.type, path) == .Invalid { 655 | return .Invalid; 656 | } 657 | } 658 | 659 | case ^Named: 660 | if t.entity.pkg != c.pkg { 661 | return .Valid; 662 | } 663 | 664 | if t.underlying == &btype[.invalid] { 665 | t.state = .Invalid; 666 | return .Invalid; 667 | } 668 | 669 | #partial switch t.state { 670 | case .Unknown: 671 | t.state = .Processing; 672 | 673 | create_path := false; 674 | temp_path: [dynamic]^Entity; 675 | p := path; 676 | if p == nil { 677 | create_path = true; 678 | p = &temp_path; 679 | } 680 | defer if create_path { 681 | delete(temp_path); 682 | } 683 | 684 | append(p, t.entity); 685 | t.state = check_valid_type(c, t.original, p); 686 | pop(p); 687 | 688 | case .Processing: // Cycle! 689 | for tname, i in path { 690 | if t.entity.pkg != c.pkg { 691 | panic("internal-error for type cycle"); 692 | } 693 | 694 | if tname == t.entity { 695 | spath: []^Entity; 696 | if path != nil { 697 | spath = path[i:]; 698 | } 699 | check_cycle_error(c, spath); 700 | t.state = .Invalid; 701 | t.underlying = &btype[.invalid]; 702 | return t.state; 703 | } 704 | } 705 | } 706 | return t.state; 707 | } 708 | 709 | return .Valid; 710 | } 711 | 712 | 713 | 714 | check_decl_stmt_out_of_order :: proc(c: ^Checker_Context, decl: ^Ast_Decl) { 715 | switch d in decl.variant { 716 | case ^Ast_Bad_Decl: 717 | // Ignore 718 | 719 | case ^Ast_Gen_Decl: 720 | spec_loop: for spec in d.specs { 721 | switch s in spec.variant { 722 | case ^Ast_Import_Spec: 723 | check_error(s.pos, "import declarations are not allowed within a procedure"); 724 | break spec_loop; 725 | 726 | case ^Ast_Export_Spec: 727 | check_error(s.pos, "export declarations are not allowed within a procedure"); 728 | break spec_loop; 729 | 730 | case ^Ast_Value_Spec: 731 | #partial switch s.keyword.kind { 732 | case .Const: 733 | for name, i in s.names { 734 | e := new_constant(name.pos, c.pkg, name.name, nil, i128(0)); 735 | 736 | init: ^Ast_Expr = nil; 737 | if i < len(s.values) { 738 | init = s.values[i]; 739 | } 740 | e.decl = new_clone(Decl_Info{ 741 | parent = c.decl, 742 | scope = c.scope, 743 | type_expr = s.type, 744 | init_expr = init, 745 | }); 746 | append(&c.scope.delayed, e); 747 | 748 | declare_entity(c, c.scope, name, e); 749 | } 750 | check_arity_match(c, s); 751 | 752 | case .Var: 753 | // Handled later in order 754 | case: 755 | check_error(decl.pos, "invalid token: {}", s.keyword.kind); 756 | } 757 | 758 | case ^Ast_Type_Spec: 759 | e := new_type_name(s.name.pos, c.pkg, s.name.name, nil); 760 | declare_entity(c, c.scope, s.name, e); 761 | 762 | e.decl = new_clone(Decl_Info{ 763 | parent = c.decl, 764 | scope = c.scope, 765 | type_expr = s.type, 766 | is_alias = pos_is_valid(s.assign), 767 | }); 768 | append(&c.scope.delayed, e); 769 | } 770 | } 771 | 772 | case ^Ast_Proc_Decl: 773 | name := d.name.name; 774 | e := new_procedure(d.name.pos, c.pkg, name, nil); 775 | declare_entity(c, c.scope, d.name, e); 776 | e.decl = new_clone(Decl_Info{ 777 | scope = c.scope, 778 | proc_decl = d, 779 | }); 780 | append(&c.scope.delayed, e); 781 | 782 | 783 | case ^Ast_Foreign_Decl: 784 | check_error(decl.pos, "TODO {:T}", d); 785 | 786 | case: 787 | check_error(decl.pos, "invalid AST, unknown Ast_Decl {:T}", d); 788 | } 789 | } 790 | 791 | check_decl_stmt_in_order :: proc(c: ^Checker_Context, decl: ^Ast_Decl) { 792 | switch d in decl.variant { 793 | case ^Ast_Bad_Decl: 794 | // Ignore 795 | 796 | case ^Ast_Gen_Decl: 797 | spec_loop: for spec in d.specs { 798 | switch s in spec.variant { 799 | case ^Ast_Import_Spec: 800 | // ignore 801 | 802 | case ^Ast_Export_Spec: 803 | // ignore 804 | 805 | case ^Ast_Value_Spec: 806 | if s.keyword.kind == .Var { 807 | variables := make([]^Variable, len(s.names)); 808 | for name, i in s.names { 809 | variables[i] = new_variable(name.pos, c.pkg, name.name, nil); 810 | } 811 | 812 | for v, i in variables { 813 | lhs: []^Variable = nil; 814 | init: ^Ast_Expr = nil; 815 | 816 | if len(s.values) == 1 { 817 | lhs = variables; 818 | init = s.values[0]; 819 | } else { 820 | // sanity check 821 | if i < len(s.values) { 822 | init = s.values[i]; 823 | } 824 | } 825 | 826 | check_variable_decl(c, v, lhs, s.type, init); 827 | if len(s.values) == 1 { 828 | break; 829 | } 830 | } 831 | 832 | check_arity_match(c, s); 833 | 834 | for name, i in s.names { 835 | declare_entity(c, c.scope, name, variables[i]); 836 | } 837 | } 838 | 839 | case ^Ast_Type_Spec: 840 | } 841 | } 842 | 843 | case ^Ast_Proc_Decl: 844 | 845 | case ^Ast_Foreign_Decl: 846 | 847 | } 848 | } 849 | -------------------------------------------------------------------------------- /src/frontend/entity.odin: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import "../constant" 4 | 5 | Entity_Flag :: enum { 6 | Used, 7 | Exported, 8 | Field, 9 | Parameter, 10 | } 11 | 12 | Entity_Flags :: bit_set[Entity_Flag; u32]; 13 | 14 | Entity_Colour :: distinct u32; 15 | Entity_Colour_White :: Entity_Colour(0); 16 | Entity_Colour_Black :: Entity_Colour(1); 17 | Entity_Colour_Grey :: Entity_Colour(2); 18 | 19 | Entity :: struct { 20 | pos: Pos, 21 | pkg: ^Package, 22 | name: string, 23 | type: ^Type, 24 | 25 | decl: ^Decl_Info, 26 | 27 | ident: ^Ast_Ident, 28 | scope: ^Scope, 29 | 30 | colour: Entity_Colour, 31 | 32 | link_name: string, 33 | foreign_library: string, 34 | flags: Entity_Flags, 35 | 36 | variant: union { 37 | ^Constant, 38 | ^Variable, 39 | ^Type_Name, 40 | ^Procedure, 41 | ^Import_Name, 42 | ^Builtin, 43 | ^Nil, 44 | }, 45 | } 46 | 47 | Constant :: struct { 48 | using entity: Entity, 49 | value: constant.Value, 50 | } 51 | Variable :: struct { 52 | using entity: Entity, 53 | field_index: i32, 54 | field_src_index: i32, 55 | } 56 | Type_Name :: struct { 57 | using entity: Entity, 58 | underlying: ^Type, 59 | } 60 | Procedure :: struct { 61 | using entity: Entity, 62 | } 63 | Import_Name :: struct { 64 | using entity: Entity, 65 | import_path: string, 66 | import_name: string, 67 | import_scope: ^Scope, 68 | } 69 | Builtin :: struct { 70 | using entity: Entity, 71 | built_id: Builtin_Id, 72 | } 73 | Nil :: struct { 74 | using entity: Entity, 75 | } 76 | 77 | 78 | entity_colour_for :: proc(t: ^Type) -> Entity_Colour { 79 | if t != nil { 80 | return Entity_Colour_Black; 81 | } 82 | return Entity_Colour_White; 83 | } 84 | 85 | new_variable :: proc(pos: Pos, pkg: ^Package, name: string, type: ^Type) -> ^Variable { 86 | e := new(Variable); 87 | e.variant = e; 88 | e.pkg = pkg; 89 | e.name = name; 90 | e.type = type; 91 | e.colour = entity_colour_for(type); 92 | 93 | return e; 94 | } 95 | 96 | new_constant :: proc(pos: Pos, pkg: ^Package, name: string, type: ^Type, value: constant.Value) -> ^Constant { 97 | e := new(Constant); 98 | e.variant = e; 99 | e.pkg = pkg; 100 | e.name = name; 101 | e.type = type; 102 | e.colour = entity_colour_for(type); 103 | e.value = value; 104 | 105 | return e; 106 | } 107 | new_procedure :: proc(pos: Pos, pkg: ^Package, name: string, type: ^Type) -> ^Procedure { 108 | e := new(Procedure); 109 | e.variant = e; 110 | e.pkg = pkg; 111 | e.name = name; 112 | e.type = type; 113 | e.colour = entity_colour_for(type); 114 | 115 | return e; 116 | } 117 | 118 | 119 | new_type_name :: proc(pos: Pos, pkg: ^Package, name: string, type: ^Type) -> ^Type_Name { 120 | e := new(Type_Name); 121 | e.variant = e; 122 | e.pkg = pkg; 123 | e.name = name; 124 | e.type = type; 125 | e.colour = entity_colour_for(type); 126 | return e; 127 | } 128 | 129 | new_field :: proc(pos: Pos, pkg: ^Package, name: string, type: ^Type) -> ^Variable { 130 | f := new_variable(pos, pkg, name, type); 131 | f.flags |= {.Field}; 132 | return f; 133 | } 134 | 135 | new_param :: proc(pos: Pos, pkg: ^Package, name: string, type: ^Type) -> ^Variable { 136 | f := new_variable(pos, pkg, name, type); 137 | f.flags |= {.Parameter}; 138 | return f; 139 | } 140 | 141 | new_nil_entity :: proc(pos: Pos, pkg: ^Package, name: string) -> ^Nil { 142 | e := new(Nil); 143 | e.variant = e; 144 | e.pkg = pkg; 145 | e.name = name; 146 | e.type = &btype[.untyped_nil]; 147 | e.colour = entity_colour_for(e.type); 148 | return e; 149 | } 150 | 151 | 152 | 153 | type_name_is_alias :: proc(tname: ^Type_Name) -> bool { 154 | if tname.type == nil { 155 | return false; 156 | } 157 | #partial switch t in tname.type.variant { 158 | case ^Basic: 159 | return tname.pkg != nil || t.name != tname.name; 160 | case ^Named: 161 | return tname != t.entity; 162 | } 163 | return true; 164 | } 165 | 166 | set_underlying :: proc(def: ^Named, type: ^Type) { 167 | if def != nil { 168 | def.underlying = type; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/frontend/errors.odin: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import "core:fmt" 4 | import "core:strings" 5 | import "core:sync" 6 | 7 | Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any); 8 | 9 | error_mutex: sync.Mutex; 10 | total_error_count: int; 11 | 12 | init_error_system :: proc() { 13 | sync.mutex_init(&error_mutex); 14 | } 15 | 16 | check_error :: proc(pos: Pos, msg: string, args: ..any) { 17 | sync.mutex_lock(&error_mutex); 18 | default_error_handler(pos, msg, ..args); 19 | sync.mutex_unlock(&error_mutex); 20 | } 21 | 22 | 23 | 24 | default_error_handler :: proc(pos: Pos, msg: string, args: ..any) { 25 | total_error_count += 1; 26 | fullpath := ""; 27 | if pos.file != nil { 28 | fullpath = pos.file.fullpath; 29 | } 30 | fmt.eprint(pos_string(pos), ' '); 31 | 32 | args_ := args; 33 | for arg_, i in args_ { 34 | arg := arg_; 35 | switch a in arg { 36 | case Operand: 37 | panic("internal error: ^Operand should be used"); 38 | 39 | case ^Operand: arg = operand_string(a); 40 | case Token: arg = a.text; 41 | case Token_Kind: arg = tokens[a]; 42 | 43 | case ^Type: arg = type_string(a); 44 | case ^Basic: arg = type_string(a); 45 | case ^Array: arg = type_string(a); 46 | case ^Slice: arg = type_string(a); 47 | case ^Struct: arg = type_string(a); 48 | case ^Pointer: arg = type_string(a); 49 | case ^Tuple: arg = type_string(a); 50 | case ^Signature: arg = type_string(a); 51 | case ^Named: arg = type_string(a); 52 | 53 | case Pos: arg = pos_string(a); 54 | 55 | case ^Ast_Expr: arg = expr_string(a); 56 | case ^Ast_Bad_Expr: arg = expr_string(a); 57 | case ^Ast_Key_Value_Expr: arg = expr_string(a); 58 | case ^Ast_Field_List: arg = expr_string(a); 59 | case ^Ast_Field: arg = expr_string(a); 60 | case ^Ast_Ident: arg = expr_string(a); 61 | case ^Ast_Basic_Lit: arg = expr_string(a); 62 | case ^Ast_Unary_Expr: arg = expr_string(a); 63 | case ^Ast_Binary_Expr: arg = expr_string(a); 64 | case ^Ast_Paren_Expr: arg = expr_string(a); 65 | case ^Ast_Deref_Expr: arg = expr_string(a); 66 | case ^Ast_Call_Expr: arg = expr_string(a); 67 | case ^Ast_Comp_Lit: arg = expr_string(a); 68 | case ^Ast_Proc_Lit: arg = expr_string(a); 69 | case ^Ast_Selector_Expr: arg = expr_string(a); 70 | case ^Ast_Index_Expr: arg = expr_string(a); 71 | case ^Ast_Slice_Expr: arg = expr_string(a); 72 | case ^Ast_Pointer_Type: arg = expr_string(a); 73 | case ^Ast_Array_Type: arg = expr_string(a); 74 | case ^Ast_Struct_Type: arg = expr_string(a); 75 | case ^Ast_Proc_Type: arg = expr_string(a); 76 | } 77 | 78 | args_[i] = arg; 79 | } 80 | 81 | fmt.eprintf(msg, ..args_); 82 | fmt.eprintf("\n"); 83 | } 84 | 85 | 86 | 87 | operand_string :: proc(x: ^Operand, allocator := context.allocator) -> string { 88 | write_byte :: strings.write_byte; 89 | write_string :: strings.write_string; 90 | 91 | b := strings.make_builder(allocator); 92 | if x.expr != nil { 93 | write_expr(&b, x.expr); 94 | } else { 95 | #partial switch x.mode { 96 | case .Builtin: 97 | write_string(&b, builtin_procs[x.builtin_id].name); 98 | case .Type: 99 | write_type(&b, x.type); 100 | case .Constant: 101 | fmt.sbprint(&b, x.value); 102 | } 103 | } 104 | enclose := len(b.buf) != 0; 105 | if enclose { 106 | write_string(&b, " ("); 107 | } 108 | 109 | has_type := false; 110 | switch x.mode { 111 | case .Invalid, .No_Value, .Type, .Builtin: 112 | // ignore 113 | 114 | case: fallthrough; 115 | case .Value, .Variable, .Constant: 116 | if x.type != nil { 117 | if type_is_untyped(x.type) { 118 | write_string(&b, x.type.variant.(^Basic).name); 119 | write_byte(&b, ' '); 120 | break; 121 | } 122 | has_type = true; 123 | } 124 | } 125 | 126 | write_string(&b, addressing_mode_strings[x.mode]); 127 | 128 | if has_type { 129 | if x.type != &btype[.invalid] { 130 | write_string(&b, " of type "); 131 | write_type(&b, x.type); 132 | } else { 133 | write_string(&b, " with invalid type"); 134 | } 135 | } 136 | 137 | if enclose { 138 | write_byte(&b, ')'); 139 | } 140 | 141 | return strings.to_string(b); 142 | } 143 | 144 | expr_string :: proc(x: ^Ast_Expr, allocator := context.temp_allocator) -> string { 145 | b := strings.make_builder(allocator); 146 | write_expr(&b, x); 147 | return strings.to_string(b); 148 | } 149 | 150 | write_expr :: proc(b: ^strings.Builder, expr: ^Ast_Expr) { 151 | write_byte :: strings.write_byte; 152 | write_string :: strings.write_string; 153 | 154 | switch x in expr.variant { 155 | case: 156 | write_string(b, "(bad expr)"); 157 | case ^Ast_Bad_Expr: 158 | write_string(b, "(bad expr)"); 159 | case ^Ast_Key_Value_Expr: 160 | write_string(b, "(bad expr - key value)"); 161 | case ^Ast_Field_List: 162 | write_string(b, "(bad expr - field list)"); 163 | case ^Ast_Field: 164 | write_string(b, "(bad expr - field)"); 165 | 166 | case ^Ast_Ident: 167 | write_string(b, x.name); 168 | 169 | case ^Ast_Basic_Lit: 170 | write_string(b, x.tok.text); 171 | 172 | case ^Ast_Unary_Expr: 173 | write_string(b, x.op.text); 174 | write_expr(b, x.expr); 175 | 176 | case ^Ast_Binary_Expr: 177 | write_expr(b, x.left); 178 | write_byte(b, ' '); 179 | write_string(b, x.op.text); 180 | write_byte(b, ' '); 181 | write_expr(b, x.right); 182 | 183 | case ^Ast_Paren_Expr: 184 | write_byte(b, '('); 185 | write_expr(b, x.expr); 186 | write_byte(b, ')'); 187 | 188 | case ^Ast_Deref_Expr: 189 | write_expr(b, x.expr); 190 | write_byte(b, '^'); 191 | 192 | case ^Ast_Call_Expr: 193 | write_expr(b, x.expr); 194 | write_byte(b, '('); 195 | for arg, i in x.args { 196 | if i > 0 { 197 | write_string(b, ", "); 198 | } 199 | write_expr(b, arg); 200 | } 201 | write_byte(b, ')'); 202 | 203 | case ^Ast_Comp_Lit: 204 | 205 | case ^Ast_Proc_Lit: 206 | write_byte(b, '('); 207 | write_expr(b, x.type); 208 | write_string(b, " literal)"); 209 | 210 | case ^Ast_Selector_Expr: 211 | write_expr(b, x.x); 212 | write_byte(b, '.'); 213 | write_expr(b, x.sel); 214 | 215 | case ^Ast_Index_Expr: 216 | write_expr(b, x.x); 217 | write_byte(b, '['); 218 | write_expr(b, x.index); 219 | write_byte(b, ']'); 220 | 221 | case ^Ast_Slice_Expr: 222 | write_expr(b, x.x); 223 | write_byte(b, '['); 224 | if x.low != nil { 225 | write_expr(b, x.low); 226 | } 227 | write_byte(b, ':'); 228 | if x.high != nil { 229 | write_expr(b, x.high); 230 | } 231 | 232 | write_byte(b, ']'); 233 | 234 | case ^Ast_Pointer_Type: 235 | write_byte(b, '^'); 236 | write_expr(b, x.elem); 237 | 238 | case ^Ast_Array_Type: 239 | write_byte(b, '['); 240 | if x.len != nil { 241 | write_expr(b, x.len); 242 | } 243 | write_byte(b, ']'); 244 | write_expr(b, x.elem); 245 | 246 | case ^Ast_Struct_Type: 247 | write_string(b, "struct{"); 248 | write_field_list(b, x.fields, "; "); 249 | 250 | case ^Ast_Proc_Type: 251 | write_string(b, "proc"); 252 | write_signature_expr(b, x); 253 | } 254 | } 255 | 256 | 257 | write_signature_expr :: proc(b: ^strings.Builder, sig: ^Ast_Proc_Type) { 258 | write_byte :: strings.write_byte; 259 | write_string :: strings.write_string; 260 | 261 | write_byte(b, '('); 262 | write_field_list(b, sig.params, ", "); 263 | write_byte(b, ')'); 264 | 265 | res := sig.results; 266 | n := field_count(res); 267 | if n == 0 { 268 | return; 269 | } 270 | write_byte(b, ' '); 271 | if n == 1 && len(res.list[0].names) == 0 { 272 | write_expr(b, res.list[0].type); 273 | return; 274 | } 275 | 276 | write_byte(b, '('); 277 | write_field_list(b, res, ", "); 278 | write_byte(b, ')'); 279 | } 280 | 281 | write_field_list :: proc(b: ^strings.Builder, fields: ^Ast_Field_List, sep: string) { 282 | write_byte :: strings.write_byte; 283 | write_string :: strings.write_string; 284 | 285 | for f, i in fields.list { 286 | if i > 0 { 287 | write_string(b, sep); 288 | } 289 | 290 | for name, j in f.names { 291 | if j > 0 { 292 | write_string(b, ", "); 293 | write_string(b, name.name); 294 | } 295 | } 296 | 297 | if len(f.names) > 0 { 298 | write_byte(b, ' '); 299 | } 300 | 301 | write_expr(b, f.type); 302 | } 303 | } 304 | 305 | type_string :: proc(type: ^Type, allocator := context.temp_allocator) -> string { 306 | b := strings.make_builder(allocator); 307 | write_type(&b, type); 308 | return strings.to_string(b); 309 | } 310 | 311 | 312 | write_type :: proc(b: ^strings.Builder, type: ^Type) { 313 | write_tuple :: proc(b: ^strings.Builder, t: ^Tuple, parens: bool) { 314 | if len(t.vars) == 1 && t.vars[0].name == "" { 315 | write_type(b, t.vars[0].type); 316 | return; 317 | } 318 | if parens do write_byte(b, '('); 319 | for var, i in t.vars { 320 | if i > 0 { 321 | write_string(b, ", "); 322 | } 323 | if var.name != "" { 324 | write_string(b, var.name); 325 | write_byte(b, ' '); 326 | } 327 | write_type(b, var.type); 328 | } 329 | if parens do write_byte(b, ')'); 330 | } 331 | 332 | write_byte :: strings.write_byte; 333 | write_i64 :: strings.write_i64; 334 | write_string :: strings.write_string; 335 | 336 | if type == nil { 337 | write_string(b, ""); 338 | return; 339 | } 340 | 341 | switch t in type.variant { 342 | case ^Basic: 343 | write_string(b, t.name); 344 | case ^Array: 345 | write_byte(b, '['); 346 | write_i64(b, t.len); 347 | write_byte(b, ']'); 348 | write_type(b, t.elem); 349 | 350 | case ^Slice: 351 | write_string(b, "[]"); 352 | write_type(b, t.elem); 353 | 354 | case ^Struct: 355 | write_string(b, "struct {"); 356 | for field, i in t.fields { 357 | if i > 0 { 358 | write_string(b, "; "); 359 | } 360 | if field.name != "" { 361 | write_string(b, field.name); 362 | write_byte(b, ' '); 363 | } 364 | write_type(b, field.type); 365 | } 366 | write_byte(b, '}'); 367 | 368 | case ^Pointer: 369 | write_byte(b, '^'); 370 | write_type(b, t.elem); 371 | 372 | case ^Tuple: 373 | write_tuple(b, t, true); 374 | 375 | case ^Signature: 376 | write_string(b, "proc"); 377 | write_tuple(b, t.params, true); 378 | if t.results != nil { 379 | write_tuple(b, t.results, true); 380 | } 381 | 382 | case ^Named: 383 | write_string(b, t.entity.name); 384 | } 385 | 386 | } 387 | -------------------------------------------------------------------------------- /src/frontend/expr.odin: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import "../constant" 4 | import "core:strconv" 5 | import "core:fmt" 6 | import "core:reflect" 7 | 8 | constant_from_token :: proc(tok: Token, allocator := context.allocator) -> constant.Value { 9 | #partial switch tok.kind { 10 | case .Integer: 11 | if val, ok := strconv.parse_i64(tok.text); ok { 12 | return i128(val); 13 | } else if val, ok := strconv.parse_u64(tok.text); ok { 14 | return i128(val); 15 | } 16 | case .Float: 17 | if val, ok := strconv.parse_f64(tok.text); ok { 18 | return val; 19 | } 20 | case .Rune: 21 | if r, _, _, ok := strconv.unquote_char(tok.text, '\''); ok { 22 | return i128(r); 23 | } 24 | case .String: 25 | if r, allocated, ok := strconv.unquote_string(tok.text, allocator); ok { 26 | return r; 27 | } 28 | case: 29 | panic("invalid token"); 30 | } 31 | 32 | return nil; 33 | } 34 | 35 | constant_op :: proc(op: Token_Kind) -> constant.Op { 36 | #partial switch op { 37 | case .Add: return .Add; 38 | case .Sub: return .Sub; 39 | case .Mul: return .Mul; 40 | case .Quo: return .Quo; 41 | case .Mod: return .Mod; 42 | 43 | case .And: return .And; 44 | case .Or: return .Or; 45 | case .Xor: return .Xor; 46 | case .Shl: return .Shl; 47 | case .Shr: return .Shr; 48 | case .And_Not: return .And_Not; 49 | 50 | case .Cmp_And: return .Cmp_And; 51 | case .Cmp_Or: return .Cmp_Or; 52 | 53 | case .Cmp_Eq: return .Cmp_Eq; 54 | case .Not_Eq: return .Not_Eq; 55 | case .Lt: return .Lt; 56 | case .Gt: return .Gt; 57 | case .Lt_Eq: return .Lt_Eq; 58 | case .Gt_Eq: return .Gt_Eq; 59 | 60 | case .Not: return .Not; 61 | } 62 | return .Invalid; 63 | } 64 | 65 | 66 | add_type_and_value :: proc(c: ^Checker_Context, e: ^Ast_Expr, mode: Addressing_Mode, type: ^Type, value: constant.Value) { 67 | e.tav.mode = mode; 68 | e.tav.type = type; 69 | e.tav.value = value; 70 | } 71 | 72 | Expr_Kind :: enum { 73 | Expr, 74 | Stmt, 75 | Conv, 76 | } 77 | 78 | 79 | check_expr :: proc(c: ^Checker_Context, x: ^Operand, e: ^Ast_Expr) { 80 | check_multi_expr(c, x, e); 81 | check_no_tuple(c, x); 82 | } 83 | 84 | 85 | check_expr_or_type :: proc(c: ^Checker_Context, x: ^Operand, e: ^Ast_Expr) { 86 | check_raw_expr(c, x, e, nil); 87 | check_no_tuple(c, x); 88 | if x.mode == .No_Value { 89 | check_error(e.pos, "{} used as value or type", x); 90 | x.mode = .Invalid; 91 | } 92 | } 93 | 94 | check_expr_with_type_hint :: proc(c: ^Checker_Context, x: ^Operand, e: ^Ast_Expr, type_hint: ^Type) { 95 | assert(type_hint != nil); 96 | check_raw_expr(c, x, e, type_hint); 97 | check_no_tuple(c, x); 98 | #partial switch x.mode { 99 | case: 100 | return; 101 | case .No_Value: 102 | check_error(e.pos, "{} used as value", x); 103 | case .Builtin: 104 | check_error(e.pos, "built-in procedure {} must be called", x); 105 | case .Type: 106 | check_error(e.pos, "{} is not an expression", x); 107 | } 108 | 109 | x.mode = .Invalid; 110 | } 111 | 112 | check_multi_expr :: proc(c: ^Checker_Context, x: ^Operand, e: ^Ast_Expr) { 113 | check_raw_expr(c, x, e, nil); 114 | #partial switch x.mode { 115 | case: 116 | return; 117 | case .No_Value: 118 | check_error(e.pos, "{} used as value", x); 119 | case .Builtin: 120 | check_error(e.pos, "built-in procedure {} must be called", x); 121 | case .Type: 122 | check_error(e.pos, "{} is not an expression", x); 123 | } 124 | 125 | x.mode = .Invalid; 126 | } 127 | 128 | check_no_tuple :: proc(c: ^Checker_Context, x: ^Operand) { 129 | if x.mode == .Value && x.type != nil { 130 | if t, ok := x.type.variant.(^Tuple); ok { 131 | assert(len(t.vars) != 1); 132 | check_error(x.expr.pos, "{}-valued {} where single value was expected", len(t.vars), x); 133 | x.mode = .Invalid; 134 | } 135 | } 136 | } 137 | 138 | 139 | check_raw_expr :: proc(c: ^Checker_Context, x: ^Operand, e: ^Ast_Expr, type_hint: ^Type) -> Expr_Kind { 140 | kind := check_expr_internal(c, x, e, type_hint); 141 | 142 | type: ^Type; 143 | value: constant.Value; 144 | #partial switch x.mode { 145 | case .Invalid: 146 | type = &btype[.invalid]; 147 | case .No_Value: 148 | type = nil; 149 | case .Constant: 150 | type = x.type; 151 | value = x.value; 152 | case: 153 | type = x.type; 154 | } 155 | 156 | add_type_and_value(c, e, x.mode, type, value); 157 | 158 | return kind; 159 | } 160 | 161 | 162 | check_expr_internal :: proc(c: ^Checker_Context, x: ^Operand, expr: ^Ast_Expr, type_hint: ^Type) -> Expr_Kind { 163 | expr_err :: proc(x: ^Operand, e: ^Ast_Expr) -> Expr_Kind { 164 | x.mode = .Invalid; 165 | x.expr = e; 166 | return .Stmt; 167 | } 168 | assert(expr != nil); 169 | // check_error(expr.pos, "{} {}", reflect.union_variant_typeid(expr.variant), expr); 170 | 171 | x.mode = .Invalid; 172 | x.type = &btype[.invalid]; 173 | 174 | switch e in expr.variant { 175 | case ^Ast_Bad_Expr: 176 | return expr_err(x, expr); 177 | 178 | case ^Ast_Ident: 179 | check_ident(c, x, e, nil, false); 180 | 181 | case ^Ast_Basic_Lit: 182 | operand_set_constant(x, e.tok); 183 | if x.mode == .Invalid { 184 | check_error(expr.pos, "compiler-error: invalid basic literal {}", expr); 185 | return expr_err(x, expr); 186 | } 187 | 188 | case ^Ast_Unary_Expr: 189 | check_error(expr.pos, "TODO(bill): ^Ast_Unary_Expr"); 190 | check_expr(c, x, e.expr); 191 | if x.mode == .Invalid { 192 | return expr_err(x, expr); 193 | } 194 | 195 | case ^Ast_Binary_Expr: 196 | check_binary(c, x, e, e.left, e.right, e.op.kind); 197 | 198 | case ^Ast_Paren_Expr: 199 | kind := check_raw_expr(c, x, e.expr, nil); 200 | x.expr = e; 201 | return kind; 202 | 203 | case ^Ast_Deref_Expr: 204 | check_expr(c, x, e.expr); 205 | if x.mode == .Invalid { 206 | return expr_err(x, expr); 207 | } 208 | 209 | if pt, ok := type_underlying(x.type).variant.(^Pointer); ok { 210 | x.mode = .Variable; 211 | x.type = pt.elem; 212 | } else { 213 | check_error(e.pos, "cannot dereference {}", x); 214 | return expr_err(x, expr); 215 | } 216 | 217 | case ^Ast_Call_Expr: 218 | return check_call(c, x, e); 219 | 220 | case ^Ast_Comp_Lit: 221 | check_error(expr.pos, "TODO(bill): ^Ast_Comp_Lit"); 222 | return expr_err(x, expr); 223 | 224 | 225 | case ^Ast_Proc_Lit: 226 | check_error(expr.pos, "TODO(bill): ^Ast_Proc_Lit"); 227 | return expr_err(x, expr); 228 | 229 | 230 | case ^Ast_Selector_Expr: 231 | check_error(expr.pos, "TODO(bill): ^Ast_Selector_Expr"); 232 | return expr_err(x, expr); 233 | 234 | 235 | case ^Ast_Index_Expr: 236 | check_error(expr.pos, "TODO(bill): ^Ast_Index_Expr"); 237 | return expr_err(x, expr); 238 | 239 | 240 | case ^Ast_Slice_Expr: 241 | check_error(expr.pos, "TODO(bill): ^Ast_Slice_Expr"); 242 | return expr_err(x, expr); 243 | 244 | 245 | case ^Ast_Key_Value_Expr: 246 | check_error(expr.pos, "TODO(bill): ^Ast_Key_Value_Expr"); 247 | return expr_err(x, expr); 248 | 249 | 250 | case ^Ast_Pointer_Type, ^Ast_Array_Type, ^Ast_Struct_Type, ^Ast_Proc_Type: 251 | x.mode = .Type; 252 | x.type = check_type(c, expr); 253 | 254 | case ^Ast_Field, ^Ast_Field_List: 255 | panic("invalid expression type"); 256 | case: 257 | panic("unknown expression type"); 258 | } 259 | 260 | x.expr = expr; 261 | return .Expr; 262 | } 263 | 264 | 265 | check_comparison :: proc(c: ^Checker_Context, x, y: ^Operand, op: Token_Kind) { 266 | if is_assignable_to(c, x, y.type) || is_assignable_to(c, y, x.type) { 267 | ok := false; 268 | #partial switch op { 269 | case .Cmp_Eq, .Not_Eq: 270 | ok = (type_is_comparable(x.type) && type_is_comparable(y.type)) || 271 | (is_operand_nil(x) && type_has_nil(y.type)) || 272 | (is_operand_nil(y) && type_has_nil(x.type)); 273 | 274 | case .Lt, .Lt_Eq, .Gt, .Gt_Eq: 275 | ok = type_is_ordered(x.type) && type_is_ordered(y.type); 276 | 277 | case: 278 | unreachable(); 279 | } 280 | 281 | if !ok { 282 | type := x.type; 283 | if is_operand_nil(x) { 284 | type = y.type; 285 | } 286 | check_error(x.expr.pos, "cannot compare {} {} {} (operator {} not defined for {})", x.expr, op, y.expr, op, type); 287 | x.mode = .Invalid; 288 | return; 289 | } 290 | } else { 291 | check_error(x.expr.pos, "cannot compare {} {} {} (mismatched types {} and {})", x.expr, op, y.expr, x.type, y.type); 292 | x.mode = .Invalid; 293 | return; 294 | } 295 | 296 | if x.mode == .Constant && y.mode == .Constant { 297 | x.value = constant.binary_op(x.value, constant_op(op), y.value); 298 | } 299 | 300 | x.type = &btype[.untyped_bool]; 301 | } 302 | 303 | Op_Predicate :: #type proc(t: ^Type) -> bool; 304 | 305 | check_op :: proc(c: ^Checker_Context, preds: [Token_Kind]Op_Predicate, x: ^Operand, op: Token_Kind) -> bool { 306 | if pred := preds[op]; pred != nil { 307 | if !pred(x.type) { 308 | check_error(x.expr.pos, "operator {} not defined for {}", op, x); 309 | return false; 310 | } 311 | return true; 312 | } 313 | check_error(x.expr.pos, "invalid AST: unknown operator {}", op); 314 | return false; 315 | } 316 | 317 | unary_op_preds := [Token_Kind]Op_Predicate { 318 | .Add = type_is_numeric, 319 | .Sub = type_is_numeric, 320 | 321 | .Xor = type_is_integer, 322 | .Not = type_is_boolean, 323 | }; 324 | 325 | binary_op_preds := [Token_Kind]Op_Predicate { 326 | .Add = type_is_numeric, 327 | .Sub = type_is_numeric, 328 | .Mul = type_is_numeric, 329 | .Quo = type_is_numeric, 330 | .Mod = type_is_numeric, 331 | 332 | .And = type_is_integer, 333 | .Or = type_is_integer, 334 | .Xor = type_is_integer, 335 | .And_Not = type_is_integer, 336 | 337 | .Cmp_And = type_is_boolean, 338 | .Cmp_Or = type_is_boolean, 339 | }; 340 | 341 | 342 | 343 | check_unary :: proc(c: ^Checker_Context, x: ^Operand, e: ^Ast_Unary_Expr, op: Token_Kind) { 344 | if op == .And { 345 | if x.mode != .Variable { 346 | check_error(x.expr.pos, "cannot take address of {}", x); 347 | x.mode = .Invalid; 348 | return; 349 | } 350 | x.mode = .Value; 351 | x.type = new_pointer(x.type); 352 | return; 353 | } 354 | 355 | if !check_op(c, unary_op_preds, x, op) { 356 | x.mode = .Invalid; 357 | return; 358 | } 359 | 360 | if x.mode == .Constant { 361 | type := type_underlying(x.type).variant.(^Basic); 362 | x.value = constant.unary_op(constant_op(op), x.value); 363 | if type_is_typed(type) { 364 | if e != nil { 365 | x.expr = e; 366 | } 367 | check_representable_as_constant(c, x, type); 368 | } 369 | return; 370 | } 371 | 372 | x.mode = .Value; 373 | } 374 | 375 | 376 | 377 | check_binary :: proc(c: ^Checker_Context, x: ^Operand, e: ^Ast_Binary_Expr, lhs, rhs: ^Ast_Expr, op: Token_Kind) { 378 | y := &Operand{}; 379 | 380 | check_expr(c, x, lhs); 381 | check_expr(c, y, rhs); 382 | if x.mode == .Invalid { 383 | return; 384 | } 385 | if y.mode == .Invalid { 386 | x.mode = .Invalid; 387 | x.expr = y.expr; 388 | return; 389 | } 390 | 391 | if is_comparison(op) { 392 | check_comparison(c, x, y, op); 393 | return; 394 | } 395 | 396 | if !are_identical(x.type, y.type) { 397 | if x.type != &btype[.invalid] && y.type != &btype[.invalid] { 398 | check_error(x.expr.pos, "mismatched types {} and {}", x.type, y.type); 399 | } 400 | x.mode = .Invalid; 401 | return; 402 | } 403 | 404 | if !check_op(c, binary_op_preds, x, op) { 405 | x.mode = .Invalid; 406 | return; 407 | } 408 | 409 | if op == .Quo || op == .Mod { 410 | if (x.mode == .Constant || type_is_integer(x.type)) && y.mode == .Constant && constant.sign(y.value) == 0 { 411 | check_error(y.expr.pos, "division by zero"); 412 | x.mode = .Invalid; 413 | return; 414 | } 415 | } 416 | 417 | if x.mode == .Constant && y.mode == .Constant { 418 | xval := x.value; 419 | yval := y.value; 420 | 421 | type := type_underlying(x.type).variant.(^Basic); 422 | x.value = constant.binary_op(xval, constant_op(op), yval); 423 | if type_is_typed(type) { 424 | if e != nil { 425 | x.expr = e; 426 | } 427 | check_representable_as_constant(c, x, type); 428 | } 429 | return; 430 | } 431 | 432 | x.mode = .Value; 433 | } 434 | 435 | 436 | 437 | representable_as_constant :: proc(c: ^Checker_Context, value: constant.Value, t: ^Basic, rounded: ^constant.Value) -> bool { 438 | if value == nil { 439 | // ignore propagated errors 440 | return true; 441 | } 442 | 443 | switch { 444 | case type_is_integer(t): 445 | x, ok := constant.as_int(value); 446 | if !ok { 447 | return false; 448 | } 449 | if rounded != nil { 450 | rounded^ = x; 451 | } 452 | 453 | if x, ok := x.(i128); ok { 454 | #partial switch t.kind { 455 | case .i8: 456 | s :: 8; 457 | return -1<<(s-1) <= x && x <= 1<<(s-1)-1; 458 | case .i16: 459 | s :: 16; 460 | return -1<<(s-1) <= x && x <= 1<<(s-1)-1; 461 | case .i32: 462 | s :: 32; 463 | return -1<<(s-1) <= x && x <= 1<<(s-1)-1; 464 | case .i64, .untyped_int: 465 | return true; 466 | case .isize: 467 | s := i64(SIZES.word_size*8); 468 | return -1< bool { 536 | panic("TODO: is_convertible_to"); 537 | return false; 538 | } 539 | 540 | check_conversion :: proc(c: ^Checker_Context, x: ^Operand, T: ^Type) -> bool { 541 | ok := false; 542 | switch { 543 | case x.mode == .Constant && is_const_type(T): 544 | t := type_underlying(T).variant.(^Basic); 545 | ok = representable_as_constant(c, x.value, t, &x.value); 546 | case is_convertible_to(c, x, T): 547 | x.mode = .Value; 548 | ok = true; 549 | } 550 | 551 | if !ok { 552 | check_error(x.expr.pos, "cannot convert {} to {}", x, T); 553 | x.mode = .Invalid; 554 | return false; 555 | } 556 | 557 | x.type = T; 558 | return true; 559 | } 560 | -------------------------------------------------------------------------------- /src/frontend/parser.odin: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import "core:mem" 4 | import "core:fmt" 5 | import "intrinsics" 6 | 7 | Parser :: struct { 8 | file: ^File, 9 | tok: Tokenizer, 10 | 11 | err: Error_Handler, 12 | 13 | prev_tok: Token, 14 | curr_tok: Token, 15 | 16 | expr_level: int, 17 | 18 | sync_pos: Pos, 19 | sync_count: int, 20 | 21 | error_count: int, 22 | 23 | node_allocator: mem.Allocator, 24 | } 25 | 26 | MAX_SYNC_COUNT :: 10; 27 | 28 | Parse_Spec_Proc :: #type proc(p: ^Parser, keyword: Token, check_semicolon: bool) -> ^Ast_Spec; 29 | 30 | parser_error :: proc(p: ^Parser, pos: Pos, msg: string, args: ..any) { 31 | if p.err != nil { 32 | p.err(pos, msg, ..args); 33 | } 34 | p.file.syntax_error_count += 1; 35 | p.error_count += 1; 36 | } 37 | 38 | new_node :: proc(p: ^Parser, $T: typeid) -> ^T { 39 | if p.node_allocator.procedure == nil { 40 | p.node_allocator = context.allocator; 41 | } 42 | n := new(T, p.node_allocator); 43 | n.variant = n; 44 | return n; 45 | } 46 | 47 | unparen :: proc(expr: ^Ast_Expr) -> ^Ast_Expr { 48 | x := expr; 49 | for { 50 | if p, is_paren := x.variant.(^Ast_Paren_Expr); is_paren { 51 | x = p.expr; 52 | } else { 53 | break; 54 | } 55 | } 56 | return x; 57 | } 58 | 59 | 60 | end_pos :: proc(tok: Token) -> Pos { 61 | pos := tok.pos; 62 | pos.offset += len(tok.text); 63 | 64 | if tok.kind == .Comment { 65 | if tok.text[:2] != "/*" { 66 | pos.column += u32(len(tok.text)); 67 | } else { 68 | for i := 0; i < len(tok.text); i += 1 { 69 | c := tok.text[i]; 70 | if c == '\n' { 71 | pos.line += 1; 72 | pos.column = 1; 73 | } else { 74 | pos.column += 1; 75 | } 76 | } 77 | } 78 | } else { 79 | pos.column += u32(len(tok.text)); 80 | } 81 | return pos; 82 | } 83 | safe_pos :: proc(p: ^Parser, pos: Pos) -> Pos { 84 | if 0 <= pos.offset && pos.offset < len(p.file.src) { 85 | return pos; 86 | } 87 | return Pos{ 88 | file = p.file, 89 | offset = len(p.file.src), 90 | line = u32(p.tok.line_count), 91 | column = 1, 92 | }; 93 | } 94 | 95 | 96 | next_token0 :: proc(p: ^Parser) -> bool { 97 | p.curr_tok = scan(&p.tok); 98 | if p.curr_tok.kind == .EOF { 99 | return false; 100 | } 101 | return true; 102 | } 103 | 104 | consume_comment :: proc(p: ^Parser) -> (tok: Token, end_line: int) { 105 | tok = p.curr_tok; 106 | assert(tok.kind == .Comment); 107 | end_line = int(tok.pos.line); 108 | 109 | if tok.text[1] == '*' { 110 | for c in tok.text { 111 | if c == '\n' { 112 | end_line += 1; 113 | } 114 | } 115 | } 116 | 117 | _ = next_token0(p); 118 | if p.curr_tok.pos.line > tok.pos.line { 119 | end_line += 1; 120 | } 121 | 122 | return; 123 | } 124 | 125 | 126 | consume_comment_group :: proc(p: ^Parser, n: int) -> (end_line: int) { 127 | end_line = int(p.curr_tok.pos.line); 128 | for p.curr_tok.kind == .Comment && 129 | int(p.curr_tok.pos.line) <= end_line+n { 130 | comment: Token; 131 | comment, end_line = consume_comment(p); 132 | } 133 | return; 134 | } 135 | 136 | consume_comment_groups :: proc(p: ^Parser, prev: Token) { 137 | if p.curr_tok.kind == .Comment { 138 | end_line := 0; 139 | 140 | if p.curr_tok.pos.line == prev.pos.line { 141 | end_line = consume_comment_group(p, 0); 142 | } 143 | 144 | end_line = -1; 145 | for p.curr_tok.kind == .Comment { 146 | end_line = consume_comment_group(p, 1); 147 | } 148 | assert(p.curr_tok.kind != .Comment); 149 | } 150 | } 151 | 152 | 153 | advance_token :: proc(p: ^Parser) -> Token { 154 | p.prev_tok = p.curr_tok; 155 | prev := p.prev_tok; 156 | if next_token0(p) { 157 | consume_comment_groups(p, prev); 158 | } 159 | return prev; 160 | } 161 | 162 | peek_token :: proc(p: ^Parser, amount: uint) -> Token_Kind { 163 | prev_state := p.tok.state; 164 | prev_curr_tok := p.curr_tok; 165 | tok := prev_curr_tok; 166 | defer { 167 | p.tok.state = prev_state; 168 | p.curr_tok = prev_curr_tok; 169 | } 170 | 171 | for i in 0.. Token { 192 | prev := p.curr_tok; 193 | if prev.kind != kind { 194 | e := to_string(kind); 195 | g := to_string(prev.kind); 196 | if prev.text == "\n" { 197 | g = "newline"; 198 | } 199 | parser_error(p, prev.pos, "expected '{}', got '{}'", e, g); 200 | } 201 | advance_token(p); 202 | return prev; 203 | } 204 | 205 | expect_token_after :: proc(p: ^Parser, kind: Token_Kind, msg: string) -> Token { 206 | prev := p.curr_tok; 207 | if prev.kind != kind { 208 | e := to_string(kind); 209 | g := to_string(prev.kind); 210 | if prev.text == "\n" { 211 | g = "newline"; 212 | } 213 | parser_error(p, prev.pos, "expected '{}' after {}, got '{}'", e, msg, g); 214 | } 215 | advance_token(p); 216 | return prev; 217 | } 218 | 219 | expect_closing :: proc(p: ^Parser, kind: Token_Kind, ctx: string) -> Token { 220 | prev := p.curr_tok; 221 | if prev.kind != kind && prev.kind == .Semicolon && prev.text == "\n" { 222 | parser_error(p, prev.pos, "missing ',' before newline in {}", ctx); 223 | advance_token(p); 224 | } 225 | return expect_token(p, kind); 226 | } 227 | 228 | 229 | expect_semicolon :: proc(p: ^Parser) { 230 | if p.curr_tok.kind != .Close_Brace || p.curr_tok.kind != .Close_Paren { 231 | #partial switch p.curr_tok.kind { 232 | case .Semicolon: 233 | advance_token(p); 234 | case .Comma: 235 | parser_error(p, p.curr_tok.pos, "expected ';'"); 236 | advance_token(p); 237 | case: 238 | parser_error(p, p.curr_tok.pos, "expected ';'"); 239 | parser_fix_sync(p, &_stmt_start_map); 240 | } 241 | } 242 | } 243 | 244 | allow_token :: proc(p: ^Parser, kind: Token_Kind) -> bool { 245 | if p.curr_tok.kind == kind { 246 | advance_token(p); 247 | return true; 248 | } 249 | return false; 250 | } 251 | 252 | 253 | is_blank_ident :: proc{ 254 | is_blank_ident_string, 255 | is_blank_ident_token, 256 | is_blank_ident_node, 257 | }; 258 | is_blank_ident_string :: inline proc(str: string) -> bool { 259 | return str == "_"; 260 | } 261 | is_blank_ident_token :: inline proc(tok: Token) -> bool { 262 | if tok.kind == .Ident { 263 | return is_blank_ident_string(tok.text); 264 | } 265 | return false; 266 | } 267 | is_blank_ident_node :: inline proc(node: ^Ast_Expr) -> bool { 268 | if ident, ok := node.variant.(^Ast_Ident); ok { 269 | return is_blank_ident(ident.name); 270 | } 271 | return true; 272 | } 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | parse_file :: proc(p: ^Parser, file: ^File) -> bool { 281 | assert(file != nil); 282 | 283 | { 284 | p.prev_tok = {}; 285 | p.curr_tok = {}; 286 | p.expr_level = 0; 287 | } 288 | 289 | p.file = file; 290 | tokenizer_init(&p.tok, file); 291 | if p.tok.ch <= 0 { 292 | return true; 293 | } 294 | 295 | advance_token(p); 296 | consume_comment_groups(p, p.prev_tok); 297 | 298 | if p.file.syntax_error_count > 0 { 299 | return false; 300 | } 301 | 302 | assert(p.file.decls == nil); 303 | p.file.decls = make([dynamic]^Ast_Decl); 304 | 305 | for p.curr_tok.kind != .EOF { 306 | decl := parse_decl(p, &_decl_start_map); 307 | append(&p.file.decls, decl); 308 | } 309 | return true; 310 | } 311 | 312 | 313 | parse_decl :: proc(p: ^Parser, sync: ^[Token_Kind]bool) -> ^Ast_Decl { 314 | f: Parse_Spec_Proc; 315 | #partial switch p.curr_tok.kind { 316 | case .Import: 317 | f = parse_import_spec; 318 | case .Const, .Var: 319 | f = parse_value_spec; 320 | case .Type: 321 | f = parse_type_spec; 322 | case .Export: 323 | f = parse_export_spec; 324 | case .Foreign: 325 | return parse_foreign_decl(p, sync); 326 | case .Proc: 327 | return parse_proc_decl(p); 328 | case: 329 | tok := p.curr_tok; 330 | parser_expect_error(p, tok.pos, "declaration"); 331 | parser_fix_sync(p, sync); 332 | bad := new_node(p, Ast_Bad_Decl); 333 | bad.pos = tok.pos; 334 | bad.end = safe_pos(p, p.curr_tok.pos); 335 | return bad; 336 | } 337 | assert(f != nil); 338 | return parse_gen_decl(p, p.curr_tok.kind, f); 339 | } 340 | 341 | 342 | parse_gen_decl :: proc(p: ^Parser, keyword: Token_Kind, f: Parse_Spec_Proc, allow_grouping := true) -> ^Ast_Gen_Decl { 343 | tok := expect_token(p, keyword); 344 | open, close: Token; 345 | specs := make([dynamic]^Ast_Spec, 0, 0); 346 | 347 | if allow_grouping && p.curr_tok.kind == .Open_Paren { 348 | open = expect_token(p, .Open_Paren); 349 | for i := 0; p.curr_tok.kind != .Close_Paren && p.curr_tok.kind != .EOF; i += 1 { 350 | append(&specs, f(p, tok, true)); 351 | } 352 | close = expect_token(p, .Close_Paren); 353 | expect_semicolon(p); 354 | } else { 355 | reserve(&specs, 1); 356 | append(&specs, f(p, tok, allow_grouping)); 357 | } 358 | 359 | decl := new_node(p, Ast_Gen_Decl); 360 | decl.pos = tok.pos; 361 | decl.end = end_pos(close) if pos_is_valid(close.pos) else specs[len(specs)-1].end; 362 | 363 | decl.tok = tok; 364 | decl.open_paren = open.pos; 365 | decl.specs = specs[:]; 366 | decl.close_paren = close.pos; 367 | 368 | return decl; 369 | } 370 | 371 | 372 | parse_import_spec :: proc(p: ^Parser, keyword: Token, _: bool) -> ^Ast_Spec { 373 | name: ^Ast_Ident; 374 | if p.curr_tok.kind == .Ident { 375 | name = parse_ident(p); 376 | } 377 | 378 | 379 | path_tok := p.curr_tok; 380 | path: string; 381 | if path_tok.kind == .String { 382 | path = path_tok.text; 383 | advance_token(p); 384 | } else { 385 | expect_token(p, .String); 386 | } 387 | expect_semicolon(p); 388 | 389 | path_node := new_node(p, Ast_Basic_Lit); 390 | path_node.pos = path_tok.pos; 391 | path_node.end = end_pos(path_tok); 392 | path_node.tok = path_tok; 393 | 394 | spec := new_node(p, Ast_Import_Spec); 395 | spec.pos = keyword.pos; 396 | spec.end = end_pos(path_tok); 397 | spec.name = name; 398 | spec.path = path_node; 399 | 400 | return spec; 401 | } 402 | 403 | parse_value_spec :: proc(p: ^Parser, keyword: Token, check_semicolon := true) -> ^Ast_Spec { 404 | start := p.curr_tok; 405 | pos := p.curr_tok.pos; 406 | names := parse_ident_list(p); 407 | type := parse_try_type(p); 408 | values: []^Ast_Expr; 409 | 410 | if allow_token(p, .Assign) { 411 | values = parse_rhs_list(p); 412 | } 413 | if check_semicolon { 414 | expect_semicolon(p); 415 | } 416 | 417 | #partial switch keyword.kind { 418 | case .Var: 419 | if type == nil && values == nil { 420 | parser_error(p, pos, "missing variable type or initialization"); 421 | } 422 | case .Const: 423 | if values == nil && type != nil { 424 | parser_error(p, pos, "missing constant value"); 425 | } 426 | } 427 | 428 | spec := new_node(p, Ast_Value_Spec); 429 | spec.pos = keyword.pos; 430 | spec.end = end_pos(start); 431 | if values != nil { 432 | spec.end = values[len(values)-1].end; 433 | } else if type != nil { 434 | spec.end = type.end; 435 | } else if names != nil { 436 | spec.end = names[len(names)-1].end; 437 | } 438 | 439 | spec.keyword = keyword; 440 | spec.names = names; 441 | spec.type = type; 442 | spec.values = values; 443 | 444 | return spec; 445 | } 446 | 447 | parse_type_spec :: proc(p: ^Parser, keyword: Token, _: bool) -> ^Ast_Spec { 448 | start := p.curr_tok; 449 | pos := p.curr_tok.pos; 450 | 451 | spec := new_node(p, Ast_Type_Spec); 452 | spec.pos = pos; 453 | spec.name = parse_ident(p); 454 | 455 | if p.curr_tok.kind == .Assign { 456 | spec.assign = advance_token(p).pos; 457 | } 458 | spec.type = parse_type(p); 459 | spec.end = spec.type.end; 460 | 461 | expect_semicolon(p); 462 | 463 | return spec; 464 | } 465 | 466 | parse_export_spec :: proc(p: ^Parser, keyword: Token, _: bool) -> ^Ast_Spec { 467 | start := p.curr_tok; 468 | pos := p.curr_tok.pos; 469 | 470 | decl := parse_decl(p, &_decl_start_map); 471 | switch d in decl.variant { 472 | case ^Ast_Bad_Decl: 473 | // ignore 474 | case ^Ast_Gen_Decl: 475 | #partial switch d.tok.kind { 476 | case .Var: 477 | // Okay 478 | 479 | case .Import, .Type, .Const: 480 | parser_error(p, decl.pos, "unexpected {} declaration in 'export' declaration", d.tok.text); 481 | 482 | case .Export: 483 | parser_error(p, decl.pos, "unexpected nested 'export' declaration"); 484 | 485 | } 486 | case ^Ast_Proc_Decl: 487 | // Okay 488 | case ^Ast_Foreign_Decl: 489 | parser_error(p, decl.pos, "unexpected foreign declaration in 'export' declaration"); 490 | } 491 | 492 | spec := new_node(p, Ast_Export_Spec); 493 | spec.pos = pos; 494 | spec.end = decl.end; 495 | spec.decl = decl; 496 | 497 | return spec; 498 | } 499 | 500 | 501 | parse_nested_proc_decl :: proc(p: ^Parser, sync: ^[Token_Kind]bool) -> ^Ast_Decl { 502 | decl := parse_decl(p, sync); 503 | switch d in decl.variant { 504 | case ^Ast_Bad_Decl: 505 | // Ignore 506 | case ^Ast_Gen_Decl: 507 | #partial switch d.tok.kind { 508 | case .Import: parser_error(p, d.pos, "unexpected 'import' declaration within a foreign declaration"); 509 | case .Type: parser_error(p, d.pos, "unexpected 'type' declaration within a foreign declaration"); 510 | case .Const: parser_error(p, d.pos, "unexpected 'const' declaration within a foreign declaration"); 511 | case .Var: 512 | var_loop: for spec in d.specs { 513 | switch s in spec.variant { 514 | case ^Ast_Import_Spec, ^Ast_Type_Spec, ^Ast_Export_Spec: 515 | // Ignore 516 | case ^Ast_Value_Spec: 517 | if s.keyword.kind != d.tok.kind { 518 | continue var_loop; 519 | } 520 | if len(s.values) > 0 { 521 | parser_error(p, d.pos, "foreign var declarations must not have initialization"); 522 | continue var_loop; 523 | } 524 | } 525 | } 526 | } 527 | case ^Ast_Proc_Decl: 528 | if d.body != nil { 529 | parser_error(p, d.pos, "foreign procedure not expecting a body"); 530 | } 531 | 532 | case ^Ast_Foreign_Decl: 533 | parser_error(p, d.pos, "unexpected nested foreign declaration"); 534 | } 535 | 536 | return decl; 537 | } 538 | 539 | parse_foreign_decl :: proc(p: ^Parser, sync: ^[Token_Kind]bool) -> ^Ast_Decl { 540 | tok := expect_token(p, .Foreign); 541 | pos := p.curr_tok.pos; 542 | 543 | lib := expect_token(p, .String); 544 | 545 | open, close: Token; 546 | decls := make([dynamic]^Ast_Decl, 0, 0); 547 | 548 | if p.curr_tok.kind == .Open_Paren { 549 | open = expect_token(p, .Open_Paren); 550 | for i := 0; p.curr_tok.kind != .Close_Paren && p.curr_tok.kind != .EOF; i += 1 { 551 | decl := parse_nested_proc_decl(p, sync); 552 | append(&decls, decl); 553 | } 554 | close = expect_token(p, .Close_Paren); 555 | expect_semicolon(p); 556 | } else { 557 | decl := parse_nested_proc_decl(p, sync); 558 | reserve(&decls, 1); 559 | append(&decls, decl); 560 | } 561 | 562 | 563 | decl := new_node(p, Ast_Foreign_Decl); 564 | decl.pos = tok.pos; 565 | decl.end = end_pos(close) if pos_is_valid(close.pos) else decls[len(decls)-1].end; 566 | 567 | decl.tok = tok; 568 | decl.lib = lib; 569 | 570 | decl.open_paren = open.pos; 571 | decl.decls = decls[:]; 572 | decl.close_paren = close.pos; 573 | 574 | return decl; 575 | } 576 | 577 | parse_proc_decl :: proc(p: ^Parser) -> ^Ast_Proc_Decl { 578 | tok := expect_token(p, .Proc); 579 | pos := tok.pos; 580 | 581 | name := parse_ident(p); 582 | 583 | params, results := parse_signature(p); 584 | 585 | body: ^Ast_Block_Stmt; 586 | if p.curr_tok.kind == .Open_Brace { 587 | body = parse_body(p); 588 | expect_semicolon(p); 589 | } else if p.curr_tok.kind == .Semicolon { 590 | expect_semicolon(p); 591 | if p.curr_tok.kind == .Open_Brace { 592 | parser_error(p, p.curr_tok.pos, "unexpected semicolon or newline before {"); 593 | body = parse_body(p); 594 | expect_semicolon(p); 595 | } 596 | } else { 597 | expect_semicolon(p); 598 | } 599 | 600 | type := new_node(p, Ast_Proc_Type); 601 | type.pos = tok.pos; 602 | type.end = results.end if results != nil else params.end; 603 | type.tok = tok; 604 | type.params = params; 605 | type.results = results; 606 | 607 | decl := new_node(p, Ast_Proc_Decl); 608 | decl.pos = pos; 609 | decl.end = body.end if body != nil else type.end; 610 | decl.name = name; 611 | decl.type = type; 612 | decl.body = body; 613 | 614 | return decl; 615 | } 616 | 617 | 618 | parse_stmt_list :: proc(p: ^Parser) -> []^Ast_Stmt { 619 | list: [dynamic]^Ast_Stmt; 620 | for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .Case && p.curr_tok.kind != .EOF { 621 | if stmt := parse_stmt(p); stmt != nil { 622 | append(&list, stmt); 623 | } 624 | } 625 | return list[:]; 626 | } 627 | 628 | 629 | parse_stmt :: proc(p: ^Parser) -> ^Ast_Stmt { 630 | #partial switch p.curr_tok.kind { 631 | case .Proc: 632 | if peek_token(p, 1) == .Ident { 633 | decl := parse_proc_decl(p); 634 | s := new_node(p, Ast_Decl_Stmt); 635 | s.pos, s.end = decl.pos, s.end; 636 | s.decl = decl; 637 | return s; 638 | } 639 | fallthrough; 640 | 641 | case .Ident, .Integer, .Float, .Rune, .String, .Open_Paren, 642 | .Open_Bracket, .Struct, .Pointer, 643 | .Add, .Sub, .And, .Xor, .Not: 644 | s := parser_simple_stmt(p, .Label_Ok); 645 | if _, ok := s.variant.(^Ast_Labeled_Stmt); !ok { 646 | expect_semicolon(p); 647 | } 648 | return s; 649 | 650 | case .Var, .Const, .Type: 651 | decl := parse_decl(p, &_stmt_start_map); 652 | s := new_node(p, Ast_Decl_Stmt); 653 | s.pos, s.end = decl.pos, s.end; 654 | s.decl = decl; 655 | return s; 656 | 657 | 658 | case .Open_Brace: 659 | s := parse_block_stmt(p); 660 | expect_semicolon(p); 661 | return s; 662 | 663 | case .Break, .Continue, .Fallthrough: 664 | tok := advance_token(p); 665 | label: ^Ast_Ident; 666 | if tok.kind != .Fallthrough && p.curr_tok.kind == .Ident { 667 | label = parse_ident(p); 668 | } 669 | expect_semicolon(p); 670 | 671 | stmt := new_node(p, Ast_Branch_Stmt); 672 | stmt.pos = tok.pos; 673 | stmt.end = label.end if label != nil else end_pos(tok); 674 | stmt.tok = tok; 675 | stmt.label = label; 676 | return stmt; 677 | 678 | case .Defer: 679 | tok := advance_token(p); 680 | stmt := parse_stmt(p); 681 | if inner, ok := stmt.variant.(^Ast_Defer_Stmt); ok { 682 | parser_error(p, inner.pos, "illegal nested defer statement"); 683 | stmt = inner.stmt; 684 | } 685 | s := new_node(p, Ast_Defer_Stmt); 686 | s.pos = tok.pos; 687 | s.end = stmt.end; 688 | s.tok = tok; 689 | s.stmt = stmt; 690 | return s; 691 | 692 | case .If: 693 | return parse_if_stmt(p); 694 | 695 | case .Switch: 696 | return parse_switch_stmt(p); 697 | 698 | case .For: 699 | return parse_for_stmt(p); 700 | 701 | case .Return: 702 | tok := expect_token(p, .Return); 703 | results: []^Ast_Expr; 704 | if p.curr_tok.kind != .Semicolon && p.curr_tok.kind != .Close_Brace { 705 | results = parse_rhs_list(p); 706 | } 707 | expect_semicolon(p); 708 | s := new_node(p, Ast_Return_Stmt); 709 | s.pos = tok.pos; 710 | s.end = results[len(results)-1].end if len(results) != 0 else end_pos(tok); 711 | s.tok_pos = tok.pos; 712 | s.results = results; 713 | return s; 714 | 715 | case .Semicolon: // Handle implicit semicolons regardless 716 | s := new_node(p, Ast_Empty_Stmt); 717 | s.pos, s.end = p.curr_tok.pos, end_pos(p.curr_tok); 718 | s.semicolon = p.curr_tok.pos; 719 | s.implicit = p.curr_tok.text == "\n"; 720 | advance_token(p); 721 | return s; 722 | 723 | case .Close_Brace: // Semicolon can be ommited before a closing '}' 724 | s := new_node(p, Ast_Empty_Stmt); 725 | s.pos, s.end = p.curr_tok.pos, end_pos(p.curr_tok); 726 | s.semicolon = p.curr_tok.pos; 727 | s.implicit = true; 728 | return s; 729 | 730 | case: 731 | pos := p.curr_tok.pos; 732 | parser_error(p, pos, "expected statement"); 733 | parser_fix_sync(p, &_stmt_start_map); 734 | s := new_node(p, Ast_Bad_Stmt); 735 | s.pos = pos; 736 | s.end = p.curr_tok.pos; 737 | return s; 738 | } 739 | return nil; 740 | } 741 | 742 | 743 | parse_if_stmt :: proc(p: ^Parser) -> ^Ast_If_Stmt { 744 | tok := expect_token(p, .If); 745 | 746 | init: ^Ast_Stmt = nil; 747 | cond: ^Ast_Expr = nil; 748 | header: { 749 | if p.curr_tok.kind == .Open_Brace { 750 | parser_error(p, p.curr_tok.pos, "missing condition in if statement"); 751 | break header; 752 | } 753 | 754 | prev_level := p.expr_level; 755 | defer p.expr_level = prev_level; 756 | p.expr_level = -1; 757 | 758 | if p.curr_tok.kind != .Semicolon { 759 | init = parser_simple_stmt(p, .Normal); 760 | } 761 | 762 | cond_stmt: ^Ast_Stmt; 763 | semi: Token; 764 | 765 | if p.curr_tok.kind != .Open_Brace { 766 | if p.curr_tok.kind == .Semicolon { 767 | semi = p.curr_tok; 768 | advance_token(p); 769 | } else { 770 | expect_semicolon(p); 771 | } 772 | if p.curr_tok.kind != .Open_Brace { 773 | cond_stmt = parser_simple_stmt(p, .Normal); 774 | } 775 | } else { 776 | cond_stmt = init; 777 | init = nil; 778 | } 779 | 780 | if cond_stmt != nil { 781 | cond = parser_conv_to_expr(p, cond_stmt, "boolean expression"); 782 | } else if pos_is_valid(semi.pos) { 783 | if semi.text == "\n" { 784 | parser_error(p, semi.pos, "unexpected newline, expected '{' after if clause"); 785 | } else { 786 | parser_error(p, semi.pos, "missing condition in if statement"); 787 | } 788 | } 789 | 790 | if cond == nil { 791 | be := new_node(p, Ast_Bad_Expr); 792 | be.pos = p.curr_tok.pos; 793 | be.end = end_pos(p.curr_tok); 794 | cond = be; 795 | } 796 | } 797 | 798 | body := parse_block_stmt(p); 799 | 800 | else_stmt: ^Ast_Stmt; 801 | if allow_token(p, .Else) { 802 | #partial switch p.curr_tok.kind { 803 | case .If: 804 | else_stmt = parse_if_stmt(p); 805 | case .Open_Brace: 806 | else_stmt = parse_block_stmt(p); 807 | expect_semicolon(p); 808 | case: 809 | parser_error(p, p.curr_tok.pos, "execpted if statement of block"); 810 | bs := new_node(p, Ast_Bad_Stmt); 811 | bs.pos = p.curr_tok.pos; 812 | bs.end = end_pos(p.curr_tok); 813 | else_stmt = bs; 814 | } 815 | } else { 816 | expect_semicolon(p); 817 | } 818 | 819 | s := new_node(p, Ast_If_Stmt); 820 | s.pos = tok.pos; 821 | s.end = else_stmt.end if else_stmt != nil else body.end; 822 | s.if_pos = tok.pos; 823 | s.init = init; 824 | s.cond = cond; 825 | s.body = body; 826 | s.else_stmt = else_stmt; 827 | 828 | return s; 829 | } 830 | 831 | parse_for_stmt :: proc(p: ^Parser) -> ^Ast_For_Stmt { 832 | tok := expect_token(p, .For); 833 | stmt1, stmt2, stmt3: ^Ast_Stmt; 834 | if p.curr_tok.kind != .Open_Brace { 835 | prev_level := p.expr_level; 836 | defer p.expr_level = prev_level; 837 | p.expr_level = -1; 838 | 839 | if p.curr_tok.kind != .Semicolon { 840 | stmt2 = parser_simple_stmt(p, .Normal); 841 | } 842 | if p.curr_tok.kind == .Semicolon { 843 | advance_token(p); 844 | stmt1 = stmt2; 845 | stmt2 = nil; 846 | if p.curr_tok.kind != .Semicolon { 847 | stmt2 = parser_simple_stmt(p, .Normal); 848 | } 849 | expect_semicolon(p); 850 | if p.curr_tok.kind != .Open_Brace { 851 | stmt3 = parser_simple_stmt(p, .Normal); 852 | } 853 | } 854 | } 855 | 856 | body := parse_block_stmt(p); 857 | expect_semicolon(p); 858 | 859 | s := new_node(p, Ast_For_Stmt); 860 | s.pos = tok.pos; 861 | s.end = body.end; 862 | s.init = stmt1; 863 | s.cond = parser_conv_to_expr(p, stmt2, "boolean expression"); 864 | s.post = stmt3; 865 | s.body = body; 866 | return s; 867 | } 868 | 869 | parse_case_clause :: proc(p: ^Parser) -> ^Ast_Case_Clause { 870 | tok := expect_token(p, .Case); 871 | clauses: []^Ast_Expr; 872 | if p.curr_tok.kind != .Colon { 873 | clauses = parse_rhs_list(p); 874 | } 875 | colon := expect_token(p, .Colon); 876 | body := parse_stmt_list(p); 877 | 878 | c := new_node(p, Ast_Case_Clause); 879 | c.pos = tok.pos; 880 | c.end = body[len(body)-1].end if len(body) != 0 else end_pos(colon); 881 | c.tok = tok; 882 | c.clauses = clauses; 883 | c.colon = colon.pos; 884 | c.body = body; 885 | 886 | return c; 887 | } 888 | 889 | parse_switch_stmt :: proc(p: ^Parser) -> ^Ast_Switch_Stmt { 890 | tok := expect_token(p, .Switch); 891 | stmt1, stmt2: ^Ast_Stmt; 892 | 893 | if p.curr_tok.kind != .Open_Brace { 894 | prev_level := p.expr_level; 895 | defer p.expr_level = prev_level; 896 | p.expr_level = -1; 897 | 898 | if p.curr_tok.kind != .Semicolon { 899 | stmt2 = parser_simple_stmt(p, .Normal); 900 | } 901 | 902 | if p.curr_tok.kind == .Semicolon { 903 | advance_token(p); 904 | stmt1 = stmt2; 905 | stmt2 = nil; 906 | if p.curr_tok.kind != .Open_Brace { 907 | stmt2 = parser_simple_stmt(p, .Normal); 908 | } 909 | } 910 | } 911 | 912 | open := expect_token(p, .Open_Brace); 913 | clauses: [dynamic]^Ast_Case_Clause; 914 | 915 | for p.curr_tok.kind == .Case { 916 | append(&clauses, parse_case_clause(p)); 917 | } 918 | 919 | close := expect_token(p, .Close_Brace); 920 | expect_semicolon(p); 921 | 922 | s := new_node(p, Ast_Switch_Stmt); 923 | s.pos = tok.pos; 924 | s.end = end_pos(close); 925 | s.init = stmt1; 926 | s.cond = parser_conv_to_expr(p, stmt2, "switch expression"); 927 | s.open = open.pos; 928 | s.clauses = clauses[:]; 929 | s.close = close.pos; 930 | 931 | return s; 932 | 933 | } 934 | 935 | 936 | 937 | Simple_Stmt_Mode :: enum { 938 | Normal, 939 | Label_Ok, 940 | } 941 | 942 | parser_simple_stmt :: proc(p: ^Parser, mode: Simple_Stmt_Mode) -> ^Ast_Stmt { 943 | #partial switch p.curr_tok.kind { 944 | case .Var, .Const: 945 | decl := parse_gen_decl(p, p.curr_tok.kind, parse_value_spec, false); 946 | s := new_node(p, Ast_Decl_Stmt); 947 | s.pos, s.end = decl.pos, s.end; 948 | s.decl = decl; 949 | return s; 950 | } 951 | 952 | lhs := parse_lhs_list(p); 953 | 954 | #partial switch p.curr_tok.kind { 955 | case .Assign, 956 | .Add_Assign, .Sub_Assign, .Mul_Assign, .Quo_Assign, .Mod_Assign, 957 | .And_Assign, .Or_Assign, .Xor_Assign, .Shl_Assign, .Shr_Assign, .And_Not_Assign: 958 | op := advance_token(p); 959 | rhs := parse_rhs_list(p); 960 | 961 | s := new_node(p, Ast_Assign_Stmt); 962 | s.pos = lhs[0].pos; 963 | s.end = rhs[len(rhs)-1].end; 964 | s.lhs = lhs; 965 | s.op = op; 966 | s.rhs = rhs; 967 | return s; 968 | } 969 | 970 | if len(lhs) > 1 { 971 | parser_error(p, lhs[0].pos, "expected 1 expression, got {}", len(lhs)); 972 | } 973 | 974 | if p.curr_tok.kind == .Colon { 975 | colon := advance_token(p); 976 | if label, ok := lhs[0].variant.(^Ast_Ident); mode == .Label_Ok && ok { 977 | stmt := parse_stmt(p); 978 | if inner, is_label := stmt.variant.(^Ast_Labeled_Stmt); is_label { 979 | parser_error(p, inner.pos, "illegal nested label declaration"); 980 | stmt = inner.stmt; 981 | } 982 | 983 | s := new_node(p, Ast_Labeled_Stmt); 984 | s.pos = lhs[0].pos; 985 | s.end = stmt.end; 986 | s.colon = colon.pos; 987 | s.stmt = stmt; 988 | return s; 989 | } 990 | parser_error(p, colon.pos, "illegal label declaration"); 991 | 992 | bs := new_node(p, Ast_Bad_Stmt); 993 | bs.pos = lhs[0].pos; 994 | bs.end = end_pos(colon); 995 | return bs; 996 | } 997 | 998 | es := new_node(p, Ast_Expr_Stmt); 999 | es.pos = lhs[0].pos; 1000 | es.end = lhs[0].end; 1001 | es.expr = lhs[0]; 1002 | 1003 | return es; 1004 | } 1005 | 1006 | parser_conv_to_expr :: proc(p: ^Parser, s: ^Ast_Stmt, want: string) -> ^Ast_Expr { 1007 | if s == nil { 1008 | return nil; 1009 | } 1010 | 1011 | if es, ok := s.variant.(^Ast_Expr_Stmt); ok { 1012 | return parser_check_expr(p, es.expr); 1013 | } 1014 | 1015 | found := "simple statement"; 1016 | if _, ok := s.variant.(^Ast_Assign_Stmt); ok { 1017 | found = "assignment"; 1018 | } 1019 | parser_error(p, s.pos, "expected {}, found {}", want, found); 1020 | be := new_node(p, Ast_Bad_Expr); 1021 | be.pos = s.pos; 1022 | be.end = s.end; 1023 | return be; 1024 | } 1025 | 1026 | 1027 | parse_block_stmt :: proc(p: ^Parser) -> ^Ast_Block_Stmt { 1028 | open := expect_token(p, .Open_Brace); 1029 | stmts := parse_stmt_list(p); 1030 | close := expect_token(p, .Close_Brace); 1031 | 1032 | body := new_node(p, Ast_Block_Stmt); 1033 | body.pos = open.pos; 1034 | body.end = end_pos(close); 1035 | body.open = open.pos; 1036 | body.close = close.pos; 1037 | body.stmts = stmts; 1038 | 1039 | return body; 1040 | } 1041 | 1042 | parse_body :: proc(p: ^Parser) -> ^Ast_Block_Stmt { 1043 | return parse_block_stmt(p); 1044 | } 1045 | 1046 | parse_signature :: proc(p: ^Parser) -> (params, results: ^Ast_Field_List) { 1047 | params = parse_parameters(p); 1048 | results = parse_result(p); 1049 | return; 1050 | } 1051 | 1052 | parse_var_type :: proc(p: ^Parser) -> ^Ast_Expr { 1053 | // NOTE(bill): Preparing for variadic procedures 1054 | type := parse_try_var_type(p); 1055 | if type == nil { 1056 | pos := p.curr_tok.pos; 1057 | parser_error(p, pos, "expected a type"); 1058 | advance_token(p); 1059 | bad := new_node(p, Ast_Bad_Expr); 1060 | bad.pos = pos; 1061 | bad.end = safe_pos(p, p.curr_tok.pos); 1062 | return bad; 1063 | } 1064 | return type; 1065 | } 1066 | 1067 | parse_try_var_type :: proc(p: ^Parser) -> ^Ast_Expr { 1068 | return parse_try_type(p); 1069 | } 1070 | 1071 | make_ident_list :: proc(p: ^Parser, list: []^Ast_Expr) -> []^Ast_Ident { 1072 | idents := make([]^Ast_Ident, len(list)); 1073 | for x, i in list { 1074 | ident, is_ident := x.variant.(^Ast_Ident); 1075 | if !is_ident { 1076 | if _, is_bad := x.variant.(^Ast_Bad_Expr); !is_bad { 1077 | parser_error(p, x.pos, "expected identifer"); 1078 | } 1079 | ident = new_node(p, Ast_Ident); 1080 | ident.pos = x.pos; 1081 | ident.end = x.end; 1082 | ident.name = "_"; 1083 | } 1084 | idents[i] = ident; 1085 | 1086 | } 1087 | return idents; 1088 | } 1089 | 1090 | 1091 | parse_parameters_list :: proc(p: ^Parser) -> []^Ast_Field { 1092 | list: [dynamic]^Ast_Expr; 1093 | for { 1094 | item := parse_var_type(p); 1095 | append(&list, item); 1096 | if p.curr_tok.kind != .Comma { 1097 | break; 1098 | } 1099 | advance_token(p); 1100 | if p.curr_tok.kind == .Close_Paren { 1101 | break; 1102 | } 1103 | } 1104 | 1105 | if type := parse_try_var_type(p); type != nil { 1106 | params: [dynamic]^Ast_Field; 1107 | 1108 | idents := make_ident_list(p, list[:]); 1109 | field := new_node(p, Ast_Field); 1110 | field.pos = list[len(list)-1].pos; 1111 | field.end = type.end; 1112 | field.names = idents; 1113 | field.type = type; 1114 | append(¶ms, field); 1115 | 1116 | if !parser_at_comma(p, "parameter list", .Close_Paren) { 1117 | return params[:]; 1118 | } 1119 | advance_token(p); 1120 | 1121 | for p.curr_tok.kind != .Close_Paren && p.curr_tok.kind != .EOF { 1122 | idents := parse_ident_list(p); 1123 | type := parse_var_type(p); 1124 | field := new_node(p, Ast_Field); 1125 | field.pos = idents[len(idents)-1].pos; 1126 | field.end = type.end; 1127 | field.names = idents; 1128 | field.type = type; 1129 | append(¶ms, field); 1130 | 1131 | if !parser_at_comma(p, "parameter list", .Close_Paren) { 1132 | break; 1133 | } 1134 | advance_token(p); 1135 | 1136 | } 1137 | 1138 | return params[:]; 1139 | } 1140 | 1141 | params := make([]^Ast_Field, len(list)); 1142 | for typ, i in params { 1143 | type := list[i]; 1144 | field := new_node(p, Ast_Field); 1145 | field.pos = type.pos; 1146 | field.end = type.end; 1147 | field.type = type; 1148 | params[i] = field; 1149 | } 1150 | return params; 1151 | } 1152 | 1153 | parse_parameters :: proc(p: ^Parser) -> ^Ast_Field_List { 1154 | list: []^Ast_Field; 1155 | open := expect_token(p, .Open_Paren); 1156 | 1157 | if p.curr_tok.kind != .Close_Paren { 1158 | list = parse_parameters_list(p); 1159 | } 1160 | 1161 | close := expect_token(p, .Close_Paren); 1162 | 1163 | 1164 | fields := new_node(p, Ast_Field_List); 1165 | fields.pos = open.pos; 1166 | fields.end = end_pos(close); 1167 | fields.open = open.pos; 1168 | fields.list = list; 1169 | fields.close = close.pos; 1170 | return fields; 1171 | } 1172 | 1173 | parse_result :: proc(p: ^Parser) -> ^Ast_Field_List { 1174 | if p.curr_tok.kind == .Open_Paren { 1175 | return parse_parameters(p); 1176 | } 1177 | 1178 | type := parse_try_type(p); 1179 | if type != nil { 1180 | list := make([]^Ast_Field, 1); 1181 | list[0] = new_node(p, Ast_Field); 1182 | list[0].pos = type.pos; 1183 | list[0].end = type.end; 1184 | 1185 | fields := new_node(p, Ast_Field_List); 1186 | fields.pos = list[0].pos; 1187 | fields.end = list[0].end; 1188 | fields.list = list; 1189 | return fields; 1190 | } 1191 | 1192 | return nil; 1193 | } 1194 | 1195 | 1196 | 1197 | 1198 | parse_ident :: proc(p: ^Parser) -> ^Ast_Ident { 1199 | tok := expect_token(p, .Ident); 1200 | node := new_node(p, Ast_Ident); 1201 | node.pos = tok.pos; 1202 | node.end = end_pos(tok); 1203 | node.name = tok.text; 1204 | return node; 1205 | } 1206 | 1207 | 1208 | parse_ident_list :: proc(p: ^Parser) -> []^Ast_Ident { 1209 | list := make([dynamic]^Ast_Ident, 0, 1); 1210 | append(&list, parse_ident(p)); 1211 | for allow_token(p, .Comma) { 1212 | append(&list, parse_ident(p)); 1213 | } 1214 | return list[:]; 1215 | } 1216 | 1217 | parse_rhs :: proc(p: ^Parser) -> ^Ast_Expr { 1218 | return parse_expr(p, false); 1219 | } 1220 | 1221 | parse_lhs_list :: proc(p: ^Parser) -> []^Ast_Expr { 1222 | return parse_expr_list(p, true); 1223 | } 1224 | 1225 | parse_rhs_list :: proc(p: ^Parser) -> []^Ast_Expr { 1226 | return parse_expr_list(p, false); 1227 | } 1228 | 1229 | parse_expr_list :: proc(p: ^Parser, is_lhs: bool) -> []^Ast_Expr { 1230 | list := make([dynamic]^Ast_Expr, 0, 1); 1231 | append(&list, parser_check_expr(p, parse_expr(p, is_lhs))); 1232 | for allow_token(p, .Comma) { 1233 | append(&list, parser_check_expr(p, parse_expr(p, is_lhs))); 1234 | } 1235 | return list[:]; 1236 | } 1237 | 1238 | parse_expr :: proc(p: ^Parser, is_lhs: bool) -> ^Ast_Expr { 1239 | return parse_binary_expr(p, is_lhs, 0+1); 1240 | } 1241 | 1242 | parser_check_expr :: proc(p: ^Parser, expr: ^Ast_Expr) -> ^Ast_Expr { 1243 | x := unparen(expr); 1244 | #partial switch _ in x.variant { 1245 | case ^Ast_Paren_Expr: 1246 | unreachable(); 1247 | case ^Ast_Bad_Expr: 1248 | case ^Ast_Ident: 1249 | case ^Ast_Basic_Lit: 1250 | case ^Ast_Comp_Lit: 1251 | case ^Ast_Proc_Lit: 1252 | case ^Ast_Selector_Expr: 1253 | case ^Ast_Index_Expr: 1254 | case ^Ast_Slice_Expr: 1255 | case ^Ast_Call_Expr: 1256 | case ^Ast_Unary_Expr: 1257 | case ^Ast_Binary_Expr: 1258 | case: 1259 | parser_error(p, x.pos, "expected expression"); 1260 | bad := new_node(p, Ast_Bad_Expr); 1261 | bad.pos = x.pos; 1262 | bad.end = safe_pos(p, x.end); 1263 | return bad; 1264 | } 1265 | return expr; 1266 | } 1267 | 1268 | parser_check_expr_or_type :: proc(p: ^Parser, expr: ^Ast_Expr) -> ^Ast_Expr { 1269 | x := unparen(expr); 1270 | #partial switch _ in x.variant { 1271 | case ^Ast_Paren_Expr: 1272 | unreachable(); 1273 | } 1274 | 1275 | return expr; 1276 | } 1277 | 1278 | 1279 | parse_binary_expr :: proc(p: ^Parser, is_lhs: bool, prec_init: int) -> ^Ast_Expr { 1280 | x := parse_unary_expr(p, is_lhs); 1281 | for { 1282 | op_prec := token_precedence(p.curr_tok.kind); 1283 | if op_prec < prec_init { 1284 | return x; 1285 | } 1286 | op := advance_token(p); 1287 | 1288 | y := parse_binary_expr(p, false, op_prec+1); 1289 | be := new_node(p, Ast_Binary_Expr); 1290 | be.left = parser_check_expr(p, x); 1291 | be.op = op; 1292 | be.right = parser_check_expr(p, y); 1293 | be.pos = be.left.pos; 1294 | be.end = be.right.end; 1295 | x = be; 1296 | } 1297 | return x; 1298 | } 1299 | 1300 | parse_unary_expr :: proc(p: ^Parser, is_lhs: bool) -> ^Ast_Expr { 1301 | #partial switch p.curr_tok.kind { 1302 | case .Add, .Sub, .Not, .Xor, .And: 1303 | op := advance_token(p); 1304 | x := parse_unary_expr(p, false); 1305 | ue := new_node(p, Ast_Unary_Expr); 1306 | ue.pos = op.pos; 1307 | ue.end = x.end; 1308 | ue.op = op; 1309 | ue.expr = x; 1310 | return ue; 1311 | } 1312 | return parse_atom_expr(p, is_lhs); 1313 | } 1314 | 1315 | parser_at_comma :: proc(p: ^Parser, comment: string, follow: Token_Kind) -> bool { 1316 | if p.curr_tok.kind == .Comma { 1317 | return true; 1318 | } 1319 | if p.curr_tok.kind != follow { 1320 | if p.curr_tok.kind == .Semicolon && p.curr_tok.text == "\n" { 1321 | parser_error(p, p.curr_tok.pos, "missing ',' before newline"); 1322 | } else { 1323 | parser_error(p, p.curr_tok.pos, "missing ','"); 1324 | } 1325 | return true; 1326 | } 1327 | return false; 1328 | 1329 | } 1330 | 1331 | parse_atom_expr :: proc(p: ^Parser, is_lhs: bool) -> ^Ast_Expr { 1332 | lhs := is_lhs; 1333 | x := parse_operand(p, lhs); 1334 | loop: for { 1335 | #partial switch p.curr_tok.kind { 1336 | case .Period: 1337 | advance_token(p); 1338 | #partial switch p.curr_tok.kind { 1339 | case .Ident: 1340 | sel := parse_ident(p); 1341 | se := new_node(p, Ast_Selector_Expr); 1342 | x = parser_check_expr(p, x); 1343 | se.pos = x.pos; 1344 | se.end = sel.end; 1345 | se.x = x; 1346 | se.sel = sel; 1347 | x = se; 1348 | 1349 | case: 1350 | tok := p.curr_tok; 1351 | parser_error(p, tok.pos, "expected selector"); 1352 | advance_token(p); 1353 | name := tok; 1354 | name.kind = .Ident; 1355 | name.text = "_"; 1356 | sel := new_node(p, Ast_Ident); 1357 | sel.pos = name.pos; 1358 | sel.end = end_pos(name); 1359 | sel.name = name.text; 1360 | 1361 | se := new_node(p, Ast_Selector_Expr); 1362 | se.pos = x.pos; 1363 | se.end = sel.end; 1364 | se.x = x; 1365 | se.sel = sel; 1366 | x = se; 1367 | } 1368 | 1369 | case .Pointer: 1370 | x = parser_check_expr(p, x); 1371 | 1372 | op := advance_token(p); 1373 | de := new_node(p, Ast_Deref_Expr); 1374 | de.pos = x.pos; 1375 | de.end = end_pos(op); 1376 | de.expr = x; 1377 | de.op = op.pos; 1378 | 1379 | x = de; 1380 | 1381 | case .Open_Paren: 1382 | x = parser_check_expr(p, x); 1383 | 1384 | open := expect_token(p, .Open_Paren); 1385 | args := make([dynamic]^Ast_Expr, 0, 0); 1386 | for p.curr_tok.kind != .Close_Paren && p.curr_tok.kind != .EOF { 1387 | append(&args, parse_rhs_or_type(p)); 1388 | if !parser_at_comma(p, "argument list", .Close_Paren) { 1389 | break; 1390 | } 1391 | advance_token(p); 1392 | } 1393 | close := expect_token(p, .Close_Paren); 1394 | 1395 | ce := new_node(p, Ast_Call_Expr); 1396 | ce.pos = x.pos; 1397 | ce.end = end_pos(close); 1398 | ce.expr = x; 1399 | ce.open = open.pos; 1400 | ce.args = args[:]; 1401 | ce.close = close.pos; 1402 | 1403 | x = ce; 1404 | 1405 | case .Open_Bracket: 1406 | x = parser_check_expr(p, x); 1407 | 1408 | N :: 2; 1409 | open := expect_token(p, .Open_Bracket); 1410 | p.expr_level += 1; 1411 | index: [2]^Ast_Expr; 1412 | colon: Token; 1413 | colon_count := 0; 1414 | 1415 | if p.curr_tok.kind != .Colon { 1416 | index[0] = parse_rhs(p); 1417 | } 1418 | if p.curr_tok.kind == .Colon { 1419 | colon = advance_token(p); 1420 | colon_count += 1; 1421 | if p.curr_tok.kind != .Close_Bracket && p.curr_tok.kind != .EOF { 1422 | index[colon_count] = parse_rhs(p); 1423 | } 1424 | } 1425 | 1426 | p.expr_level -= 1; 1427 | close := expect_token(p, .Close_Bracket); 1428 | 1429 | if colon_count > 0 { 1430 | ie := new_node(p, Ast_Slice_Expr); 1431 | ie.pos = x.pos; 1432 | ie.end = end_pos(close); 1433 | ie.x = x; 1434 | ie.open = open.pos; 1435 | ie.low = index[0]; 1436 | ie.high = index[1]; 1437 | ie.close = close.pos; 1438 | 1439 | x = ie; 1440 | } else { 1441 | ie := new_node(p, Ast_Index_Expr); 1442 | ie.pos = x.pos; 1443 | ie.end = end_pos(close); 1444 | ie.x = x; 1445 | ie.open = open.pos; 1446 | ie.index = index[0]; 1447 | ie.close = close.pos; 1448 | 1449 | x = ie; 1450 | } 1451 | 1452 | case .Open_Brace: 1453 | if is_literal_type(x) && (p.expr_level >= 0) { 1454 | x = parse_literal_value(p, x); 1455 | } else { 1456 | break loop; 1457 | } 1458 | case: 1459 | break loop; 1460 | } 1461 | lhs = false; 1462 | } 1463 | 1464 | return x; 1465 | } 1466 | 1467 | parse_operand :: proc(p: ^Parser, is_lhs: bool) -> ^Ast_Expr { 1468 | #partial switch p.curr_tok.kind { 1469 | case .Ident: 1470 | return parse_ident(p); 1471 | case .Integer, .Float, .Rune, .String: 1472 | tok := p.curr_tok; 1473 | advance_token(p); 1474 | 1475 | x := new_node(p, Ast_Basic_Lit); 1476 | x.pos = tok.pos; 1477 | x.end = end_pos(tok); 1478 | x.tok = tok; 1479 | 1480 | return x; 1481 | case .Open_Paren: 1482 | open := expect_token(p, .Open_Paren); 1483 | p.expr_level += 1; 1484 | expr := parse_rhs_or_type(p); 1485 | p.expr_level -= 1; 1486 | close := expect_token(p, .Close_Paren); 1487 | 1488 | x := new_node(p, Ast_Paren_Expr); 1489 | x.pos = open.pos; 1490 | x.end = end_pos(close); 1491 | x.open = open.pos; 1492 | x.expr = expr; 1493 | x.close = close.pos; 1494 | return x; 1495 | 1496 | case .Proc: 1497 | return parse_proc_type_or_lit(p); 1498 | } 1499 | 1500 | if type := parse_try_type(p); type != nil { 1501 | _, is_ident := type.variant.(^Ast_Ident); 1502 | assert(!is_ident, "type cannot be identifier"); 1503 | return type; 1504 | } 1505 | 1506 | // Error 1507 | tok := p.curr_tok; 1508 | parser_error(p, tok.pos, "expected operand"); 1509 | parser_fix_sync(p, &_stmt_start_map); 1510 | bad := new_node(p, Ast_Bad_Expr); 1511 | bad.pos = tok.pos; 1512 | bad.end = end_pos(p.curr_tok); 1513 | return bad; 1514 | } 1515 | 1516 | 1517 | parse_proc_type :: proc(p: ^Parser) -> ^Ast_Proc_Type { 1518 | tok := expect_token(p, .Proc); 1519 | params, results := parse_signature(p); 1520 | 1521 | type := new_node(p, Ast_Proc_Type); 1522 | type.pos = tok.pos; 1523 | type.end = results.end if results != nil else params.end; 1524 | type.params = params; 1525 | type.results = results; 1526 | return type; 1527 | } 1528 | 1529 | parse_proc_type_or_lit :: proc(p: ^Parser) -> ^Ast_Expr { 1530 | type := parse_proc_type(p); 1531 | if p.curr_tok.kind != .Open_Brace { 1532 | return type; 1533 | } 1534 | 1535 | p.expr_level += 1; 1536 | body := parse_body(p); 1537 | p.expr_level -= 1; 1538 | 1539 | lit := new_node(p, Ast_Proc_Lit); 1540 | lit.pos = type.pos; 1541 | lit.end = body.end; 1542 | lit.type = type; 1543 | lit.body = body; 1544 | return lit; 1545 | } 1546 | 1547 | parse_value :: proc(p: ^Parser, allow_key: bool) -> ^Ast_Expr { 1548 | if p.curr_tok.kind == .Open_Brace { 1549 | return parse_literal_value(p, nil); 1550 | } 1551 | 1552 | return parser_check_expr(p, parse_expr(p, allow_key)); 1553 | } 1554 | 1555 | 1556 | parse_element :: proc(p: ^Parser) -> ^Ast_Expr { 1557 | x := parse_value(p, true); 1558 | if p.curr_tok.kind == .Assign { 1559 | assign := expect_token(p, .Assign); 1560 | key := x; 1561 | value := parse_value(p, false); 1562 | kv := new_node(p, Ast_Key_Value_Expr); 1563 | kv.pos = key.pos; 1564 | kv.end = value.end; 1565 | kv.key = key; 1566 | kv.assign = assign.pos; 1567 | kv.value = value; 1568 | x = kv; 1569 | } 1570 | 1571 | return x; 1572 | } 1573 | 1574 | parse_element_list :: proc(p: ^Parser) -> []^Ast_Expr { 1575 | list: [dynamic]^Ast_Expr; 1576 | for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF { 1577 | elem := parse_element(p); 1578 | append(&list, elem); 1579 | if !parser_at_comma(p, "compound literal", .Close_Brace) { 1580 | break; 1581 | } 1582 | advance_token(p); 1583 | } 1584 | 1585 | return list[:]; 1586 | } 1587 | 1588 | 1589 | parse_literal_value :: proc(p: ^Parser, type: ^Ast_Expr) -> ^Ast_Comp_Lit { 1590 | open := expect_token(p, .Open_Brace); 1591 | elems: []^Ast_Expr; 1592 | p.expr_level += 1; 1593 | if p.curr_tok.kind != .Close_Brace { 1594 | elems = parse_element_list(p); 1595 | } 1596 | p.expr_level -= 1; 1597 | close := expect_closing(p, .Close_Brace, "compound literal"); 1598 | 1599 | 1600 | comp := new_node(p, Ast_Comp_Lit); 1601 | comp.pos = type.pos if type != nil else open.pos; 1602 | comp.end = end_pos(close); 1603 | comp.type = type; 1604 | comp.open = open.pos; 1605 | comp.elems = elems; 1606 | comp.close = close.pos; 1607 | return comp; 1608 | } 1609 | 1610 | parse_rhs_or_type :: proc(p: ^Parser) -> ^Ast_Expr { 1611 | return parser_check_expr_or_type(p, parse_expr(p, false)); 1612 | } 1613 | 1614 | parse_field_decl :: proc(p: ^Parser) -> ^Ast_Field { 1615 | names := parse_ident_list(p); 1616 | type := parse_type(p); 1617 | expect_semicolon(p); 1618 | 1619 | field := new_node(p, Ast_Field); 1620 | field.pos = names[0].pos if len(names) > 0 else type.pos; 1621 | field.end = type.end; 1622 | field.names = names; 1623 | field.type = type; 1624 | return field; 1625 | } 1626 | 1627 | parse_try_type :: proc(p: ^Parser) -> ^Ast_Expr { 1628 | #partial switch p.curr_tok.kind { 1629 | case .Ident: 1630 | return parse_ident(p); 1631 | 1632 | case .Open_Bracket: 1633 | open := expect_token(p, .Open_Bracket); 1634 | 1635 | len: ^Ast_Expr; 1636 | 1637 | p.expr_level += 1; 1638 | if p.curr_tok.kind != .Close_Bracket { 1639 | len = parse_rhs(p); 1640 | } 1641 | p.expr_level -= 1; 1642 | 1643 | close := expect_token(p, .Close_Bracket); 1644 | 1645 | elem := parse_type(p); 1646 | 1647 | at := new_node(p, Ast_Array_Type); 1648 | at.pos = open.pos; 1649 | at.end = elem.end; 1650 | at.open = open.pos; 1651 | at.len = len; 1652 | at.close = close.pos; 1653 | at.elem = elem; 1654 | return at; 1655 | 1656 | case .Struct: 1657 | tok := expect_token(p, .Struct); 1658 | open := expect_token(p, .Open_Brace); 1659 | fields: [dynamic]^Ast_Field; 1660 | for p.curr_tok.kind == .Ident { 1661 | field := parse_field_decl(p); 1662 | append(&fields, field); 1663 | } 1664 | 1665 | close := expect_token(p, .Close_Brace); 1666 | 1667 | field_list := new_node(p, Ast_Field_List); 1668 | field_list.pos = open.pos; 1669 | field_list.end = end_pos(close); 1670 | field_list.open = open.pos; 1671 | field_list.list = fields[:]; 1672 | field_list.close = close.pos; 1673 | 1674 | st := new_node(p, Ast_Struct_Type); 1675 | st.pos = tok.pos; 1676 | st.end = end_pos(close); 1677 | st.tok = tok; 1678 | st.fields = field_list; 1679 | return st; 1680 | 1681 | case .Pointer: 1682 | tok := expect_token(p, .Pointer); 1683 | elem := parse_type(p); 1684 | 1685 | x := new_node(p, Ast_Pointer_Type); 1686 | x.pos = tok.pos; 1687 | x.end = elem.end; 1688 | x.tok = tok; 1689 | x.elem = elem; 1690 | 1691 | return x; 1692 | 1693 | case .Proc: 1694 | return parse_proc_type(p); 1695 | 1696 | case .Open_Paren: 1697 | open := expect_token(p, .Open_Paren); 1698 | type := parse_type(p); 1699 | close := expect_token(p, .Close_Paren); 1700 | 1701 | x := new_node(p, Ast_Paren_Expr); 1702 | x.pos = open.pos; 1703 | x.end = end_pos(close); 1704 | 1705 | x.open = open.pos; 1706 | x.expr = type; 1707 | x.close = close.pos; 1708 | 1709 | return x; 1710 | } 1711 | return nil; 1712 | } 1713 | 1714 | parse_type :: proc(p: ^Parser)-> ^Ast_Expr { 1715 | type := parse_try_type(p); 1716 | if type != nil { 1717 | return type; 1718 | } 1719 | 1720 | tok := p.curr_tok; 1721 | parser_error(p, tok.pos, "expected type"); 1722 | parser_fix_sync(p, &_expr_end_map); 1723 | be := new_node(p, Ast_Bad_Expr); 1724 | be.pos = tok.pos; 1725 | be.end = end_pos(p.curr_tok); 1726 | return be; 1727 | } 1728 | 1729 | 1730 | is_literal_type :: proc(x: ^Ast_Expr) -> bool { 1731 | #partial switch t in x.variant { 1732 | case ^Ast_Bad_Expr: 1733 | case ^Ast_Ident: 1734 | case ^Ast_Selector_Expr: 1735 | case ^Ast_Array_Type: 1736 | case ^Ast_Struct_Type: 1737 | case: 1738 | return false; 1739 | } 1740 | return true; 1741 | } 1742 | 1743 | 1744 | 1745 | 1746 | 1747 | parser_fix_sync :: proc(p: ^Parser, to: ^[Token_Kind]bool) { 1748 | for ; p.curr_tok.kind != .EOF; _ = advance_token(p) { 1749 | if to[p.curr_tok.kind] { 1750 | if pos_compare(p.curr_tok.pos, p.sync_pos) == 0 && p.sync_count < MAX_SYNC_COUNT { 1751 | p.sync_count += 1; 1752 | return; 1753 | } 1754 | if pos_compare(p.curr_tok.pos, p.sync_pos) > 0 { 1755 | p.sync_pos = p.curr_tok.pos; 1756 | p.sync_count = 0; 1757 | return; 1758 | } 1759 | } 1760 | } 1761 | } 1762 | 1763 | 1764 | _stmt_start_map := [Token_Kind]bool{ 1765 | .Break = true, 1766 | .Continue = true, 1767 | .Fallthrough = true, 1768 | 1769 | .Defer = true, 1770 | .If = true, 1771 | .For = true, 1772 | .Switch = true, 1773 | .Return = true, 1774 | 1775 | .Const = true, 1776 | .Var = true, 1777 | .Type = true, 1778 | }; 1779 | 1780 | _decl_start_map := [Token_Kind]bool{ 1781 | .Const = true, 1782 | .Var = true, 1783 | .Type = true, 1784 | .Proc = true, 1785 | .Import = true, 1786 | .Foreign = true, 1787 | .Export = true, 1788 | }; 1789 | 1790 | _expr_end_map := [Token_Kind]bool{ 1791 | .Semicolon = true, 1792 | .Comma = true, 1793 | .Colon = true, 1794 | .Close_Paren = true, 1795 | .Close_Bracket = true, 1796 | .Close_Brace = true, 1797 | }; 1798 | -------------------------------------------------------------------------------- /src/frontend/stmt.odin: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import "core:reflect" 4 | 5 | check_assignment :: proc(c: ^Checker_Context, x: ^Operand, T: ^Type, ctx: string) { 6 | check_no_tuple(c, x); 7 | 8 | if x.mode == .Invalid { 9 | return; 10 | } 11 | 12 | if type_is_untyped(x.type) { 13 | // TODO(bill): edge case for untyped types 14 | } 15 | 16 | if T == nil { 17 | return; 18 | } 19 | 20 | if ok := is_assignable_to(c, x, T); !ok { 21 | check_error(x.expr.pos, "cannot use '{}' as '{}' value in {}", x, T, ctx); 22 | } 23 | } 24 | 25 | 26 | is_assignable_to :: proc(c: ^Checker_Context, x: ^Operand, T: ^Type) -> (ok: bool) { 27 | if x.mode == .Invalid || T == &btype[.invalid] { 28 | return true; 29 | } 30 | 31 | V := x.type; 32 | 33 | if are_identical(V, T) { 34 | return true; 35 | } 36 | 37 | V_u := type_underlying(V); 38 | T_u := type_underlying(T); 39 | 40 | if type_is_untyped(V_u) { 41 | #partial switch t in T_u.variant { 42 | case ^Basic: 43 | if is_operand_nil(x) && t.kind == .rawptr { 44 | return true; 45 | } 46 | if x.mode == .Constant { 47 | return representable_as_constant(c, x.value, t, nil); 48 | } 49 | 50 | if V_b, ok := V_u.variant.(^Basic); ok && V_b != nil { 51 | return V_b.kind == .untyped_bool && type_is_boolean(T_u); 52 | } 53 | 54 | case ^Pointer, ^Signature, ^Slice: 55 | return is_operand_nil(x); 56 | } 57 | } 58 | 59 | return false; 60 | } 61 | 62 | 63 | open_scope :: proc(c: ^Checker_Context, s: ^Ast_Stmt, comment: string) { 64 | scope := create_scope(c.scope, s.pos, s.end); 65 | c.scope = scope; 66 | } 67 | 68 | close_scope :: proc(c: ^Checker_Context) { 69 | c.scope = c.scope.parent; 70 | } 71 | 72 | Stmt_Flag :: enum { 73 | Break_Ok, 74 | Continue_Ok, 75 | Fallthrough_Ok, 76 | } 77 | Stmt_Flags :: bit_set[Stmt_Flag]; 78 | 79 | check_stmt_list :: proc(c: ^Checker_Context, stmt_flags: Stmt_Flags, list: []^Ast_Stmt) { 80 | stmt_flags := stmt_flags; 81 | fallthrough_ok := .Fallthrough_Ok in stmt_flags; 82 | stmt_flags &~= {.Fallthrough_Ok}; 83 | stmts := trim_trailing_empty_stmts(list); 84 | 85 | for stmt, i in stmts do if s, ok := stmt.variant.(^Ast_Decl_Stmt); ok { 86 | check_decl_stmt_out_of_order(c, s.decl); 87 | } 88 | 89 | for stmt, i in stmts { 90 | inner := stmt_flags; 91 | if fallthrough_ok && i+1 == len(stmts) { 92 | inner |= {.Fallthrough_Ok}; 93 | } 94 | check_stmt(c, inner, stmt); 95 | } 96 | 97 | for e in c.scope.delayed { 98 | assert(e != nil); 99 | check_entity_decl(c, e, nil); 100 | } 101 | for e in c.scope.delayed { 102 | if e.decl.proc_decl != nil { 103 | p := e.variant.(^Procedure); 104 | sig := p.type.variant.(^Signature); 105 | ctx := c^; 106 | ctx.scope = sig.scope; 107 | ctx.decl = p.decl; 108 | ctx.proc_name = p.name; 109 | ctx.curr_proc_decl = e.decl; 110 | ctx.curr_proc_type = sig; 111 | check_proc_body(&ctx, p, e.decl); 112 | } 113 | } 114 | clear(&c.scope.delayed); 115 | delete(c.scope.delayed); 116 | } 117 | 118 | trim_trailing_empty_stmts :: proc(list: []^Ast_Stmt) -> []^Ast_Stmt { 119 | for i := len(list); i > 0; i -= 1 { 120 | if _, ok := list[i-1].variant.(^Ast_Empty_Stmt); !ok { 121 | return list[:i]; 122 | } 123 | } 124 | return nil; 125 | } 126 | 127 | check_assign_var :: proc(c: ^Checker_Context, lhs: ^Ast_Expr, x: ^Operand) -> ^Type { 128 | if x.mode == .Invalid || x.type == &btype[.invalid] { 129 | return nil; 130 | } 131 | 132 | ident, _ := unparen(lhs).variant.(^Ast_Ident); 133 | 134 | if ident != nil && ident.name == "_" { 135 | ident.entity = nil; 136 | check_assignment(c, x, nil, "assignment to _ identifier"); 137 | if x.mode == .Invalid { 138 | return nil; 139 | } 140 | return x.type; 141 | } 142 | 143 | y: Operand; 144 | check_expr(c, &y, lhs); 145 | if y.mode == .Invalid || y.type == &btype[.invalid] { 146 | return nil; 147 | } 148 | 149 | if y.mode == .Variable { 150 | // Okay 151 | } else { 152 | check_error(y.expr.pos, "cannot assign to {}", &y); 153 | return nil; 154 | } 155 | 156 | check_assignment(c, x, y.type, "assignment"); 157 | if x.mode == .Invalid { 158 | return nil; 159 | } 160 | 161 | return x.type; 162 | } 163 | 164 | 165 | check_stmt :: proc(c: ^Checker_Context, stmt_flags: Stmt_Flags, stmt: ^Ast_Stmt) { 166 | if stmt == nil { 167 | return; 168 | } 169 | // check_error(stmt.pos, "{}", reflect.union_variant_typeid(stmt.variant)); 170 | 171 | switch s in stmt.variant { 172 | case ^Ast_Bad_Stmt, ^Ast_Empty_Stmt: 173 | // Ignore 174 | 175 | case ^Ast_Expr_Stmt: 176 | x: Operand; 177 | kind := check_raw_expr(c, &x, s.expr, nil); 178 | #partial switch x.mode { 179 | case .Builtin: 180 | check_error(x.expr.pos, "{} must be called", &x); 181 | case .Type: 182 | check_error(x.expr.pos, "{} is not an expression", &x); 183 | case: 184 | if kind == .Stmt { 185 | return; 186 | } 187 | check_error(x.expr.pos, "{} is not used", &x); 188 | } 189 | 190 | case ^Ast_Decl_Stmt: 191 | check_decl_stmt_in_order(c, s.decl); 192 | 193 | case ^Ast_Labeled_Stmt: 194 | check_error(stmt.pos, "TODO(bill): {:T}", s); 195 | 196 | case ^Ast_Assign_Stmt: 197 | if s.op.kind == .Assign { 198 | if len(s.lhs) == 0 { 199 | check_error(s.pos, "invalid AST: missing left hand side in assignment"); 200 | return; 201 | } 202 | // TODO(bill): assigning 203 | } else { 204 | if len(s.lhs) != 1 || len(s.rhs) != 1 { 205 | check_error(s.pos, "assignment operation {} requires single-valued expressions", s.op.text); 206 | return; 207 | } 208 | 209 | op := assign_op(s.op.kind); 210 | if op == .Invalid { 211 | check_error(s.pos, "invalid AST: unknown assignment operator {}", s.op.text);; 212 | return; 213 | } 214 | 215 | x: Operand; 216 | check_binary(c, &x, nil, s.lhs[0], s.rhs[0], op); 217 | if x.mode == .Invalid { 218 | return; 219 | } 220 | 221 | check_assign_var(c, s.lhs[0], &x); 222 | } 223 | 224 | case ^Ast_Defer_Stmt: 225 | check_error(stmt.pos, "TODO(bill): {:T}", s); 226 | 227 | case ^Ast_Branch_Stmt: 228 | check_error(stmt.pos, "TODO(bill): {:T}", s); 229 | 230 | case ^Ast_Block_Stmt: 231 | open_scope(c, s, "block"); 232 | defer close_scope(c); 233 | 234 | check_stmt_list(c, stmt_flags, s.stmts); 235 | 236 | case ^Ast_If_Stmt: 237 | open_scope(c, s, "if"); 238 | defer close_scope(c); 239 | 240 | check_stmt(c, nil, s.init); 241 | 242 | x: Operand; 243 | check_expr(c, &x, s.cond); 244 | if x.mode != .Invalid && !type_is_boolean(x.type) { 245 | check_error(s.cond.pos, "non-boolean condition in if statement"); 246 | } 247 | 248 | check_stmt(c, stmt_flags, s.body); 249 | if s.else_stmt != nil { 250 | #partial switch e in s.else_stmt.variant { 251 | case ^Ast_Bad_Stmt: 252 | case ^Ast_If_Stmt, ^Ast_Block_Stmt: 253 | check_stmt(c, stmt_flags, s.else_stmt); 254 | case: 255 | check_error(s.else_stmt.pos, "invalid else statement in if statement"); 256 | } 257 | } 258 | 259 | case ^Ast_For_Stmt: 260 | open_scope(c, s, "for"); 261 | defer close_scope(c); 262 | 263 | check_stmt(c, nil, s.init); 264 | 265 | x: Operand; 266 | check_expr(c, &x, s.cond); 267 | if x.mode != .Invalid && !type_is_boolean(x.type) { 268 | check_error(s.cond.pos, "non-boolean condition in for statement"); 269 | } 270 | 271 | check_stmt(c, nil, s.post); 272 | check_stmt(c, stmt_flags, s.body); 273 | 274 | case ^Ast_Switch_Stmt: 275 | check_error(stmt.pos, "TODO(bill): {:T}", s); 276 | 277 | case ^Ast_Return_Stmt: 278 | check_error(stmt.pos, "TODO(bill): {:T}", s); 279 | 280 | case ^Ast_Case_Clause: 281 | check_error(stmt.pos, "TODO(bill): {:T}", s); 282 | 283 | case: 284 | check_error(stmt.pos, "invalid statement"); 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /src/frontend/token.odin: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import "core:strings" 4 | import "core:fmt" 5 | 6 | Token :: struct { 7 | kind: Token_Kind, 8 | text: string, 9 | pos: Pos, 10 | } 11 | 12 | Pos :: struct { 13 | file: ^File, 14 | offset: int, // starting at 0 15 | line: u32, // starting at 1 16 | column: u32, // starting at 1 17 | } 18 | 19 | pos_is_valid :: proc(using p: Pos, ignore_file := false) -> bool { 20 | return (file != nil || ignore_file) && offset >= 0 && line > 0 && column > 0; 21 | } 22 | 23 | pos_compare :: proc(lhs, rhs: Pos) -> int { 24 | if lhs.offset != rhs.offset { 25 | return -1 if (lhs.offset < rhs.offset) else +1; 26 | } 27 | if lhs.line != rhs.line { 28 | return -1 if (lhs.line < rhs.line) else +1; 29 | } 30 | if lhs.column != rhs.column { 31 | return -1 if (lhs.column < rhs.column) else +1; 32 | } 33 | if lhs.file == rhs.file { 34 | return 0; 35 | } 36 | if lhs.file != nil && rhs.file == nil { 37 | return -1; 38 | } 39 | if lhs.file == nil && rhs.file != nil { 40 | return +1; 41 | } 42 | return strings.compare(lhs.file.fullpath, rhs.file.fullpath); 43 | } 44 | 45 | pos_string :: proc(using p: Pos, allocator := context.temp_allocator) -> string { 46 | b := strings.make_builder(allocator); 47 | if file != nil { 48 | strings.write_string(&b, file.fullpath); 49 | } 50 | 51 | if pos_is_valid(p, true) { 52 | strings.write_byte(&b, '('); 53 | strings.write_u64(&b, u64(line)); 54 | strings.write_byte(&b, ':'); 55 | strings.write_u64(&b, u64(column)); 56 | strings.write_byte(&b, ')'); 57 | } 58 | if len(b.buf) == 0 { 59 | strings.write_byte(&b, '-'); 60 | } 61 | 62 | return strings.to_string(b); 63 | } 64 | 65 | 66 | Token_Kind :: enum u8 { 67 | Invalid, 68 | EOF, 69 | Comment, 70 | 71 | B_Literal_Begin, 72 | Ident, 73 | Integer, 74 | Float, 75 | Rune, 76 | String, 77 | B_Literal_End, 78 | 79 | B_Operator_Begin, 80 | Add, // + 81 | Sub, // - 82 | Mul, // * 83 | Quo, // / 84 | Mod, // % 85 | 86 | And, // & 87 | Or, // | 88 | Xor, // ~ 89 | Shl, // << 90 | Shr, // >> 91 | And_Not, // &~ 92 | 93 | Add_Assign, // += 94 | Sub_Assign, // -= 95 | Mul_Assign, // *= 96 | Quo_Assign, // /= 97 | Mod_Assign, // %= 98 | 99 | And_Assign, // &= 100 | Or_Assign, // |= 101 | Xor_Assign, // ~= 102 | Shl_Assign, // <<= 103 | Shr_Assign, // >>= 104 | And_Not_Assign, // &~= 105 | 106 | Cmp_And, // && 107 | Cmp_Or, // || 108 | 109 | Cmp_Eq, // == 110 | Not_Eq, // != 111 | Lt, // < 112 | Gt, // > 113 | Lt_Eq, // <= 114 | Gt_Eq, // >= 115 | 116 | Assign, // = 117 | Not, // ! 118 | Arrow_Right, // -> 119 | Pointer, // ^ 120 | 121 | Open_Paren, // ( 122 | Open_Bracket, // [ 123 | Open_Brace, // { 124 | Comma, // , 125 | Period, // . 126 | 127 | Close_Paren, // ) 128 | Close_Bracket, // ] 129 | Close_Brace, // } 130 | Semicolon, // ; 131 | Colon, // : 132 | B_Operator_End, 133 | 134 | B_Keyword_Begin, 135 | Break, 136 | Continue, 137 | Fallthrough, 138 | 139 | Case, 140 | Switch, 141 | For, 142 | If, 143 | Else, 144 | Defer, 145 | Return, 146 | 147 | Proc, 148 | Struct, 149 | Enum, 150 | Union, 151 | 152 | Import, 153 | Export, 154 | Foreign, 155 | Const, 156 | Type, 157 | Var, 158 | B_Keyword_End, 159 | }; 160 | 161 | tokens := [len(Token_Kind)]string { 162 | "Invalid", 163 | "EOF", 164 | "Comment", 165 | 166 | "", 167 | "Identifer", 168 | "Integer", 169 | "Float", 170 | "Rune", 171 | "String", 172 | "", 173 | 174 | "", 175 | "+", 176 | "-", 177 | "*", 178 | "/", 179 | "%", 180 | 181 | "&", 182 | "|", 183 | "~", 184 | "<<", 185 | ">>", 186 | "&~", 187 | 188 | "+=", 189 | "-=", 190 | "*=", 191 | "/=", 192 | "%=", 193 | 194 | "&", 195 | "|", 196 | "~", 197 | "<<", 198 | ">>", 199 | "&~", 200 | 201 | "&&", 202 | "||", 203 | 204 | "==", 205 | "!=", 206 | "<", 207 | ">", 208 | "<=", 209 | ">=", 210 | 211 | "=", 212 | "!", 213 | "->", 214 | "^", 215 | 216 | "(", 217 | "[", 218 | "{", 219 | ",", 220 | ".", 221 | 222 | ")", 223 | "]", 224 | "}", 225 | ";", 226 | ":", 227 | "", 228 | 229 | "", 230 | "break", 231 | "continue", 232 | "fallthrough", 233 | 234 | "case", 235 | "switch", 236 | "for", 237 | "if", 238 | "else", 239 | "defer", 240 | "return", 241 | 242 | "proc", 243 | "struct", 244 | "enum", 245 | "union", 246 | 247 | "import", 248 | "export", 249 | "foreign", 250 | "const", 251 | "type", 252 | "var", 253 | "", 254 | }; 255 | 256 | 257 | to_string :: proc(kind: Token_Kind) -> string { 258 | if Token_Kind.Invalid <= kind && kind < Token_Kind(len(Token_Kind)) { 259 | return tokens[kind]; 260 | } 261 | return "Invalid"; 262 | } 263 | 264 | is_literal :: proc(kind: Token_Kind) -> bool { 265 | return Token_Kind.B_Literal_Begin < kind && kind < Token_Kind.B_Literal_End; 266 | } 267 | is_operator :: proc(kind: Token_Kind) -> bool { 268 | #partial switch kind { 269 | case .B_Operator_Begin .. .B_Operator_End: 270 | return true; 271 | } 272 | return false; 273 | } 274 | is_keyword :: proc(kind: Token_Kind) -> bool { 275 | switch { 276 | case Token_Kind.B_Keyword_Begin < kind && kind < Token_Kind.B_Keyword_End: 277 | return true; 278 | } 279 | return false; 280 | } 281 | 282 | token_precedence :: proc(op: Token_Kind) -> int { 283 | #partial switch op { 284 | case .Cmp_Or: 285 | return 1; 286 | case .Cmp_And: 287 | return 2; 288 | case .Cmp_Eq, .Not_Eq, .Lt, .Lt_Eq, .Gt, .Gt_Eq: 289 | return 3; 290 | case .Add, .Sub, .Or, .Xor: 291 | return 4; 292 | case .Mul, .Quo, .Mod, .Shl, .Shr, .And, .And_Not: 293 | return 5; 294 | } 295 | return 0; 296 | } 297 | 298 | 299 | assign_op :: proc(op: Token_Kind) -> Token_Kind { 300 | #partial switch op { 301 | case .Add_Assign: return .Add; 302 | case .Sub_Assign: return .Sub; 303 | case .Mul_Assign: return .Mul; 304 | case .Quo_Assign: return .Quo; 305 | case .Mod_Assign: return .Mod; 306 | 307 | case .And_Assign: return .And; 308 | case .Or_Assign: return .Or; 309 | case .Xor_Assign: return .Xor; 310 | case .Shl_Assign: return .Shl; 311 | case .Shr_Assign: return .Shr; 312 | case .And_Not_Assign: return .And_Not; 313 | } 314 | 315 | return .Invalid; 316 | } 317 | 318 | is_comparison :: proc(op: Token_Kind) -> bool { 319 | #partial switch op { 320 | case .Cmp_Eq, .Not_Eq, .Lt, .Gt, .Lt_Eq, .Gt_Eq: 321 | return true; 322 | } 323 | return false; 324 | } 325 | -------------------------------------------------------------------------------- /src/frontend/tokenizer.odin: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import "core:fmt" 4 | import "core:unicode/utf8" 5 | 6 | Tokenizer_State :: struct { 7 | ch: rune, 8 | offset: int, 9 | read_offset: int, 10 | line_offset: int, 11 | line_count: int, 12 | insert_semi: bool, 13 | } 14 | 15 | Tokenizer :: struct { 16 | // Immutable data 17 | path: string, 18 | src: []byte, 19 | err: Error_Handler, 20 | 21 | file: ^File, 22 | 23 | using state: Tokenizer_State, 24 | 25 | // Mutable data 26 | error_count: int, 27 | } 28 | 29 | tokenizer_init :: proc(t: ^Tokenizer, file: ^File, err: Error_Handler = default_error_handler) { 30 | t.file = file; 31 | t.path = file.fullpath; 32 | t.src = file.src; 33 | t.err = err; 34 | t.ch = ' '; 35 | t.offset = 0; 36 | t.read_offset = 0; 37 | t.line_offset = 0; 38 | t.line_count = len(t.src) > 0 ? 1 : 0; 39 | t.error_count = 0; 40 | 41 | advance_rune(t); 42 | if t.ch == utf8.RUNE_BOM { 43 | advance_rune(t); 44 | } 45 | } 46 | 47 | @(private) 48 | offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> Pos { 49 | line := t.line_count; 50 | column := offset - t.line_offset + 1; 51 | 52 | return Pos { 53 | file = t.file, 54 | offset = offset, 55 | line = u32(line), 56 | column = u32(column), 57 | }; 58 | } 59 | 60 | tokenizer_error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) { 61 | pos := offset_to_pos(t, offset); 62 | if t.err != nil { 63 | t.err(pos, msg, ..args); 64 | } 65 | t.error_count += 1; 66 | } 67 | 68 | advance_rune :: proc(using t: ^Tokenizer) { 69 | if read_offset < len(src) { 70 | offset = read_offset; 71 | if ch == '\n' { 72 | line_offset = offset; 73 | line_count += 1; 74 | } 75 | r, w := rune(src[read_offset]), 1; 76 | switch { 77 | case r == 0: 78 | tokenizer_error(t, t.offset, "illegal character NUL"); 79 | case r >= utf8.RUNE_SELF: 80 | r, w = utf8.decode_rune(src[read_offset:]); 81 | if r == utf8.RUNE_ERROR && w == 1 { 82 | tokenizer_error(t, t.offset, "illegal UTF-8 encoding"); 83 | } else if r == utf8.RUNE_BOM && offset > 0 { 84 | tokenizer_error(t, t.offset, "illegal byte order mark"); 85 | } 86 | } 87 | read_offset += w; 88 | ch = r; 89 | } else { 90 | offset = len(src); 91 | if ch == '\n' { 92 | line_offset = offset; 93 | line_count += 1; 94 | } 95 | ch = -1; 96 | } 97 | } 98 | 99 | peek_byte :: proc(t: ^Tokenizer, offset := 0) -> byte { 100 | if t.read_offset+offset < len(t.src) { 101 | return t.src[t.read_offset+offset]; 102 | } 103 | return 0; 104 | } 105 | 106 | skip_whitespace :: proc(t: ^Tokenizer) { 107 | for t.ch == ' ' || 108 | t.ch == '\t' || 109 | t.ch == '\n' && !t.insert_semi || 110 | t.ch == '\r' { 111 | advance_rune(t); 112 | } 113 | } 114 | 115 | is_letter :: proc(r: rune) -> bool { 116 | if r < utf8.RUNE_SELF { 117 | switch r { 118 | case '_': 119 | return true; 120 | case 'A'..'Z', 'a'..'z': 121 | return true; 122 | } 123 | } 124 | // TODO(bill): Add unicode lookup tables 125 | return false; 126 | } 127 | is_digit :: proc(r: rune) -> bool { 128 | // TODO(bill): Add unicode lookup tables 129 | return '0' <= r && r <= '9'; 130 | } 131 | 132 | 133 | scan_comment :: proc(t: ^Tokenizer) -> string { 134 | offset := t.offset-1; 135 | next := -1; 136 | general: { 137 | if t.ch == '/' { 138 | advance_rune(t); 139 | for t.ch != '\n' && t.ch >= 0 { 140 | advance_rune(t); 141 | } 142 | 143 | next = t.offset; 144 | if t.ch == '\n' { 145 | next += 1; 146 | } 147 | break general; 148 | } 149 | 150 | /* style comment */ 151 | advance_rune(t); 152 | for t.ch >= 0 { 153 | ch := t.ch; 154 | advance_rune(t); 155 | if ch == '*' && t.ch == '/' { 156 | advance_rune(t); 157 | next = t.offset; 158 | break general; 159 | } 160 | } 161 | 162 | tokenizer_error(t, offset, "comment not terminated"); 163 | } 164 | 165 | lit := t.src[offset : t.offset]; 166 | 167 | // NOTE(bill): Strip CR for line comments 168 | for len(lit) > 2 && lit[1] == '/' && lit[len(lit)-1] == '\r' { 169 | lit = lit[:len(lit)-1]; 170 | } 171 | 172 | 173 | return string(lit); 174 | } 175 | 176 | scan_identifier :: proc(t: ^Tokenizer) -> string { 177 | offset := t.offset; 178 | 179 | for is_letter(t.ch) || is_digit(t.ch) { 180 | advance_rune(t); 181 | } 182 | 183 | return string(t.src[offset : t.offset]); 184 | } 185 | 186 | scan_string :: proc(t: ^Tokenizer) -> string { 187 | offset := t.offset-1; 188 | 189 | for { 190 | ch := t.ch; 191 | if ch == '\n' || ch < 0 { 192 | tokenizer_error(t, offset, "string literal was not terminated"); 193 | break; 194 | } 195 | advance_rune(t); 196 | if ch == '"' { 197 | break; 198 | } 199 | if ch == '\\' { 200 | scan_escape(t); 201 | } 202 | } 203 | 204 | return string(t.src[offset : t.offset]); 205 | } 206 | 207 | scan_raw_string :: proc(t: ^Tokenizer) -> string { 208 | offset := t.offset-1; 209 | 210 | for { 211 | ch := t.ch; 212 | if ch == '\n' || ch < 0 { 213 | tokenizer_error(t, offset, "raw string literal was not terminated"); 214 | break; 215 | } 216 | advance_rune(t); 217 | if ch == '`' { 218 | break; 219 | } 220 | } 221 | 222 | return string(t.src[offset : t.offset]); 223 | } 224 | 225 | digit_val :: proc(r: rune) -> int { 226 | switch r { 227 | case '0'..'9': 228 | return int(r-'0'); 229 | case 'A'..'F': 230 | return int(r-'A' + 10); 231 | case 'a'..'f': 232 | return int(r-'a' + 10); 233 | } 234 | return 16; 235 | } 236 | 237 | scan_escape :: proc(t: ^Tokenizer) -> bool { 238 | offset := t.offset; 239 | 240 | n: int; 241 | base, max: u32; 242 | switch t.ch { 243 | case 'a', 'b', 'e', 'f', 'n', 't', 'v', '\\', '\'', '\"': 244 | advance_rune(t); 245 | return true; 246 | 247 | case '0'..'7': 248 | n, base, max = 3, 8, 255; 249 | case 'x': 250 | advance_rune(t); 251 | n, base, max = 2, 16, 255; 252 | case 'u': 253 | advance_rune(t); 254 | n, base, max = 4, 16, utf8.MAX_RUNE; 255 | case 'U': 256 | advance_rune(t); 257 | n, base, max = 8, 16, utf8.MAX_RUNE; 258 | case: 259 | if t.ch < 0 { 260 | tokenizer_error(t, offset, "escape sequence was not terminated"); 261 | } else { 262 | tokenizer_error(t, offset, "unknown escape sequence"); 263 | } 264 | return false; 265 | } 266 | 267 | x: u32; 268 | for n > 0 { 269 | d := u32(digit_val(t.ch)); 270 | for d >= base { 271 | if t.ch < 0 { 272 | tokenizer_error(t, t.offset, "escape sequence was not terminated"); 273 | } else { 274 | tokenizer_error(t, t.offset, "illegal character %d in escape sequence", t.ch); 275 | } 276 | return false; 277 | } 278 | 279 | x = x*base + d; 280 | advance_rune(t); 281 | n -= 1; 282 | } 283 | 284 | if x > max || 0xd800 <= x && x <= 0xe000 { 285 | tokenizer_error(t, offset, "escape sequence is an invalid Unicode code point"); 286 | return false; 287 | } 288 | return true; 289 | } 290 | 291 | scan_rune :: proc(t: ^Tokenizer) -> string { 292 | offset := t.offset-1; 293 | valid := true; 294 | n := 0; 295 | for { 296 | ch := t.ch; 297 | if ch == '\n' || ch < 0 { 298 | if valid { 299 | tokenizer_error(t, offset, "rune literal not terminated"); 300 | valid = false; 301 | } 302 | break; 303 | } 304 | advance_rune(t); 305 | if ch == '\'' { 306 | break; 307 | } 308 | n += 1; 309 | if ch == '\\' { 310 | if !scan_escape(t) { 311 | valid = false; 312 | } 313 | } 314 | } 315 | 316 | if valid && n != 1 { 317 | tokenizer_error(t, offset, "illegal rune literal"); 318 | } 319 | 320 | return string(t.src[offset : t.offset]); 321 | } 322 | 323 | scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Token_Kind, string) { 324 | scan_mantissa :: proc(t: ^Tokenizer, base: int) { 325 | for digit_val(t.ch) < base || t.ch == '_' { 326 | advance_rune(t); 327 | } 328 | } 329 | scan_exponent :: proc(t: ^Tokenizer, kind: ^Token_Kind) { 330 | if t.ch == 'e' || t.ch == 'E' { 331 | kind^ = .Float; 332 | advance_rune(t); 333 | if t.ch == '-' || t.ch == '+' { 334 | advance_rune(t); 335 | } 336 | if digit_val(t.ch) < 10 { 337 | scan_mantissa(t, 10); 338 | } else { 339 | tokenizer_error(t, t.offset, "illegal floating-point exponent"); 340 | } 341 | } 342 | } 343 | scan_fraction :: proc(t: ^Tokenizer, kind: ^Token_Kind) -> (early_exit: bool) { 344 | if t.ch == '.' && peek_byte(t) == '.' { 345 | return true; 346 | } 347 | if t.ch == '.' { 348 | kind^ = .Float; 349 | advance_rune(t); 350 | scan_mantissa(t, 10); 351 | } 352 | return false; 353 | } 354 | 355 | 356 | offset := t.offset; 357 | kind := Token_Kind.Integer; 358 | seen_point := seen_decimal_point; 359 | 360 | if seen_point { 361 | offset -= 1; 362 | kind = .Float; 363 | scan_mantissa(t, 10); 364 | scan_exponent(t, &kind); 365 | } else { 366 | if t.ch == '0' { 367 | int_base :: inline proc(t: ^Tokenizer, kind: ^Token_Kind, base: int, msg: string) { 368 | prev := t.offset; 369 | advance_rune(t); 370 | scan_mantissa(t, base); 371 | if t.offset - prev <= 1 { 372 | kind^ = .Invalid; 373 | tokenizer_error(t, t.offset, msg); 374 | } 375 | } 376 | 377 | advance_rune(t); 378 | switch t.ch { 379 | case 'b': int_base(t, &kind, 2, "illegal binary integer"); 380 | case 'o': int_base(t, &kind, 8, "illegal octal integer"); 381 | case 'd': int_base(t, &kind, 10, "illegal decimal integer"); 382 | case 'z': int_base(t, &kind, 12, "illegal dozenal integer"); 383 | case 'x': int_base(t, &kind, 16, "illegal hexadecimal integer"); 384 | case 'h': 385 | prev := t.offset; 386 | advance_rune(t); 387 | scan_mantissa(t, 16); 388 | if t.offset - prev <= 1 { 389 | kind = .Invalid; 390 | tokenizer_error(t, t.offset, "illegal hexadecimal floating-point number"); 391 | } else { 392 | sub := t.src[prev+1 : t.offset]; 393 | digit_count := 0; 394 | for d in sub { 395 | if d != '_' { 396 | digit_count += 1; 397 | } 398 | } 399 | 400 | switch digit_count { 401 | case 8, 16: break; 402 | case: 403 | tokenizer_error(t, t.offset, "invalid hexadecimal floating-point number, expected 8 or 16 digits, got %d", digit_count); 404 | } 405 | } 406 | 407 | case: 408 | seen_point = false; 409 | scan_mantissa(t, 10); 410 | if t.ch == '.' { 411 | seen_point = true; 412 | if scan_fraction(t, &kind) { 413 | return kind, string(t.src[offset : t.offset]); 414 | } 415 | } 416 | scan_exponent(t, &kind); 417 | return kind, string(t.src[offset : t.offset]); 418 | } 419 | } 420 | } 421 | 422 | scan_mantissa(t, 10); 423 | 424 | if scan_fraction(t, &kind) { 425 | return kind, string(t.src[offset : t.offset]); 426 | } 427 | 428 | scan_exponent(t, &kind); 429 | 430 | return kind, string(t.src[offset : t.offset]); 431 | } 432 | 433 | 434 | scan :: proc(t: ^Tokenizer) -> Token { 435 | switch2 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind) -> Token_Kind { 436 | if t.ch == '=' { 437 | advance_rune(t); 438 | return tok1; 439 | } 440 | return tok0; 441 | } 442 | switch3 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2: Token_Kind) -> Token_Kind { 443 | if t.ch == '=' { 444 | advance_rune(t); 445 | return tok1; 446 | } 447 | if t.ch == ch2 { 448 | advance_rune(t); 449 | return tok2; 450 | } 451 | return tok0; 452 | } 453 | switch4 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2, tok3: Token_Kind) -> Token_Kind { 454 | if t.ch == '=' { 455 | advance_rune(t); 456 | return tok1; 457 | } 458 | if t.ch == ch2 { 459 | advance_rune(t); 460 | if t.ch == '=' { 461 | advance_rune(t); 462 | return tok3; 463 | } 464 | return tok2; 465 | } 466 | return tok0; 467 | } 468 | 469 | 470 | skip_whitespace(t); 471 | 472 | offset := t.offset; 473 | 474 | kind: Token_Kind; 475 | lit: string; 476 | pos := offset_to_pos(t, offset); 477 | 478 | insert_semi := false; 479 | switch ch := t.ch; true { 480 | case is_letter(ch): 481 | lit = scan_identifier(t); 482 | kind = .Ident; 483 | check_keyword: if len(lit) > 1 { 484 | // TODO(bill): Maybe have a hash table lookup rather than this linear search 485 | for i in Token_Kind.B_Keyword_Begin .. Token_Kind.B_Keyword_End { 486 | if lit == tokens[i] { 487 | kind = Token_Kind(i); 488 | break check_keyword; 489 | } 490 | } 491 | } 492 | #partial switch kind { 493 | case .Ident, .Break, .Continue, .Fallthrough, .Return: 494 | insert_semi = true; 495 | } 496 | 497 | case '0' <= ch && ch <= '9': 498 | insert_semi = true; 499 | kind, lit = scan_number(t, false); 500 | case: 501 | advance_rune(t); 502 | switch ch { 503 | case -1: 504 | if insert_semi { 505 | t.insert_semi = false; 506 | return Token{.Semicolon, "\n", pos}; 507 | } 508 | kind = .EOF; 509 | case '\n': 510 | t.insert_semi = false; 511 | kind = .Semicolon; 512 | lit = "\n"; 513 | 514 | 515 | case '"': 516 | insert_semi = true; 517 | kind = .String; 518 | lit = scan_string(t); 519 | case '\'': 520 | insert_semi = true; 521 | kind = .Rune; 522 | lit = scan_rune(t); 523 | case '`': 524 | insert_semi = true; 525 | kind = .String; 526 | lit = scan_raw_string(t); 527 | case '=': kind = switch2(t, .Assign, .Cmp_Eq); 528 | case '!': kind = switch2(t, .Not, .Not_Eq); 529 | case '^': kind = .Pointer; 530 | case '+': kind = switch2(t, .Add, .Add_Assign); 531 | case '-': 532 | if t.ch == '>' { 533 | advance_rune(t); 534 | kind = .Arrow_Right; 535 | } else { 536 | kind = switch2(t, .Sub, .Sub_Assign); 537 | } 538 | case '*': kind = switch2(t, .Mul, .Mul_Assign); 539 | case '/': 540 | if t.ch == '/' || t.ch == '*' { 541 | kind = .Comment; 542 | lit = scan_comment(t); 543 | } else { 544 | kind = switch2(t, .Quo, .Quo_Assign); 545 | } 546 | case '%': kind = switch2(t, .Mod, .Mod_Assign); 547 | case '&': 548 | if t.ch == '~' { 549 | advance_rune(t); 550 | kind = switch2(t, .And_Not, .And_Not_Assign); 551 | } else { 552 | kind = switch3(t, .And, .And_Assign, '&', .Cmp_And); 553 | } 554 | case '|': kind = switch3(t, .Or, .Or_Assign, '|', .Cmp_Or); 555 | case '~': kind = .Xor; 556 | case '<': kind = switch4(t, .Lt, .Lt_Eq, '<', .Shl, .Shl_Assign); 557 | case '>': kind = switch4(t, .Gt, .Gt_Eq, '>', .Shr, .Shr_Assign); 558 | 559 | case '.': 560 | if '0' <= t.ch && t.ch <= '9' { 561 | kind, lit = scan_number(t, true); 562 | } else { 563 | kind = .Period; 564 | } 565 | case ':': kind = .Colon; 566 | case ',': kind = .Comma; 567 | case ';': kind = .Semicolon; 568 | case '(': kind = .Open_Paren; 569 | case ')': kind = .Close_Paren; insert_semi = true; 570 | case '[': kind = .Open_Bracket; 571 | case ']': kind = .Close_Bracket; insert_semi = true; 572 | case '{': kind = .Open_Brace; 573 | case '}': kind = .Close_Brace; insert_semi = true; 574 | 575 | case: 576 | if ch != utf8.RUNE_BOM { 577 | tokenizer_error(t, t.offset, "illegal character '%r': %d", ch, ch); 578 | } 579 | insert_semi = t.insert_semi; // perserve the semicolon information 580 | kind = .Invalid; 581 | } 582 | } 583 | 584 | t.insert_semi = insert_semi; 585 | 586 | if lit == "" { 587 | lit = string(t.src[offset : t.offset]); 588 | } 589 | return Token{kind, lit, pos}; 590 | } 591 | -------------------------------------------------------------------------------- /src/frontend/type_expr.odin: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import "core:fmt" 4 | 5 | import "../constant" 6 | 7 | check_ident :: proc(c: ^Checker_Context, x: ^Operand, ident: ^Ast_Ident, def: ^Named, want_type: bool) { 8 | assert(ident != nil); 9 | 10 | x.mode = .Invalid; 11 | x.expr = ident; 12 | x.type = &btype[.invalid]; 13 | 14 | scope, e := scope_lookup(c.scope, ident.name); 15 | if e == nil { 16 | if ident.name == "_" { 17 | check_error(ident.pos, "cannot use _ as a value or type"); 18 | } else { 19 | check_error(ident.pos, "undeclared name: {}", ident.name); 20 | } 21 | return; 22 | } 23 | ident.entity = e; 24 | 25 | type := e.type; 26 | if _, got_type := e.variant.(^Type_Name); type == nil || got_type && want_type { 27 | check_entity_decl(c, e, def); 28 | type = e.type; 29 | } 30 | assert(type != nil); 31 | 32 | 33 | 34 | switch e in e.variant { 35 | case ^Import_Name: 36 | check_error(e.pos, "use of package {} not in selector expression", e.name); 37 | return; 38 | case ^Constant: 39 | add_decl_dep(c, e); 40 | if type == &btype[.invalid] { 41 | return; 42 | } 43 | x.value = e.value; 44 | assert(x.value != nil); 45 | x.mode = .Constant; 46 | 47 | case ^Variable: 48 | if e.pkg == c.pkg { 49 | e.flags |= {.Used}; 50 | } 51 | add_decl_dep(c, e); 52 | if type == &btype[.invalid] { 53 | return; 54 | } 55 | x.mode = .Variable; 56 | 57 | case ^Type_Name: 58 | x.mode = .Type; 59 | 60 | case ^Procedure: 61 | add_decl_dep(c, e); 62 | x.mode = .Value; 63 | 64 | case ^Builtin: 65 | x.mode = .Builtin; 66 | x.builtin_id = e.built_id; 67 | 68 | case ^Nil: 69 | x.mode = .Value; 70 | 71 | case: 72 | unreachable(); 73 | } 74 | 75 | x.type = type; 76 | } 77 | 78 | check_type :: proc(c: ^Checker_Context, e: ^Ast_Expr, def: ^Named = nil) -> ^Type { 79 | t := check_type_internal(c, e, def); 80 | assert(type_is_typed(t)); 81 | add_type_and_value(c, e, .Type, t, nil); 82 | return t; 83 | } 84 | 85 | check_type_internal :: proc(c: ^Checker_Context, expr: ^Ast_Expr, def: ^Named) -> ^Type { 86 | assert(expr != nil); 87 | #partial switch e in expr.variant { 88 | case ^Ast_Bad_Expr: 89 | // ignore 90 | 91 | case ^Ast_Ident: 92 | x: Operand; 93 | check_ident(c, &x, e, def, true); 94 | 95 | #partial switch x.mode { 96 | case .Type: 97 | type := x.type; 98 | set_underlying(def, type); 99 | return type; 100 | case .Invalid: 101 | // Ignore the error 102 | case .No_Value: 103 | check_error(e.pos, "{} used as type", e.name); 104 | case: 105 | check_error(e.pos, "{} is not a type", e.name); 106 | } 107 | 108 | case ^Ast_Paren_Expr: 109 | return check_type(c, e.expr, def); 110 | 111 | case ^Ast_Selector_Expr: 112 | panic("todo: ^Ast_Selector_Expr"); 113 | 114 | case ^Ast_Pointer_Type: 115 | 116 | type := new_type(Pointer); 117 | set_underlying(def, type); 118 | 119 | push_entity_path(c); 120 | type.elem = check_type(c, e.elem); 121 | pop_entity_path(c); 122 | 123 | return type; 124 | 125 | case ^Ast_Array_Type: 126 | if e.len != nil { 127 | type := new_type(Array); 128 | set_underlying(def, type); 129 | type.len = check_array_length(c, e.len); 130 | type.elem = check_type(c, e.elem); 131 | return type; 132 | } else { 133 | type := new_type(Slice); 134 | set_underlying(def, type); 135 | push_entity_path(c); 136 | type.elem = check_type(c, e.elem); 137 | pop_entity_path(c); 138 | return type; 139 | } 140 | 141 | case ^Ast_Struct_Type: 142 | type := new_type(Struct); 143 | set_underlying(def, type); 144 | check_struct_type(c, type, e); 145 | return type; 146 | 147 | case ^Ast_Proc_Type: 148 | type := new_type(Signature); 149 | set_underlying(def, type); 150 | check_proc_type(c, type, e); 151 | return type; 152 | 153 | case: 154 | check_error(expr.pos, "expression is not a type"); 155 | } 156 | 157 | type := &btype[.invalid]; 158 | set_underlying(def, type); 159 | return type; 160 | } 161 | 162 | 163 | 164 | check_array_length :: proc(c: ^Checker_Context, n: ^Ast_Expr) -> i64 { 165 | x: Operand; 166 | check_expr(c, &x, n); 167 | if x.mode != .Constant { 168 | if x.mode != .Invalid { 169 | check_error(n.pos, "array length {} must be constant", &x); 170 | } 171 | return -1; 172 | } 173 | if type_is_untyped(x.type) || type_is_integer(x.type) { 174 | if val, ok := constant.as_int(x.value); ok { 175 | if representable_as_constant(c, val, &btype[.isize], nil) { 176 | if n, ok := constant.as_i64(val); ok && n >= 0 { 177 | return i64(n); 178 | } 179 | check_error(n.pos, "invalid array length {}", &x); 180 | return -1; 181 | } 182 | } 183 | } 184 | check_error(n.pos, "array length {} must be integer", &x); 185 | return -1; 186 | } 187 | check_struct_type :: proc(c: ^Checker_Context, type: ^Struct, expr: ^Ast_Struct_Type) { 188 | list := expr.fields; 189 | if list == nil { 190 | return; 191 | } 192 | fields: [dynamic]^Variable; 193 | 194 | 195 | for f in list.list { 196 | assert(f != nil); 197 | assert(f.type != nil); 198 | ftype := check_type(c, f.type); 199 | assert(len(f.names) > 0); 200 | for ident in f.names { 201 | name := ident.name; 202 | field := new_field(ident.pos, c.pkg, name, ftype); 203 | field.field_index = i32(len(fields)); 204 | field.field_src_index = i32(len(fields)); 205 | append(&fields, field); 206 | ident.entity = field; 207 | } 208 | } 209 | 210 | type.fields = fields[:]; 211 | } 212 | check_proc_type :: proc(c: ^Checker_Context, sig: ^Signature, proc_type: ^Ast_Proc_Type) { 213 | scope := create_scope(c.scope, {}, {}, "procedure"); 214 | scope.kind = .Procedure; 215 | proc_type.scope = scope; 216 | 217 | params := collect_params(c, scope, proc_type.params); 218 | results := collect_params(c, scope, proc_type.results); 219 | 220 | sig.scope = scope; 221 | sig.params = new_tuple(..params); 222 | sig.results = new_tuple(..results); 223 | 224 | return; 225 | } 226 | 227 | collect_params :: proc(c: ^Checker_Context, scope: ^Scope, list: ^Ast_Field_List) -> []^Variable { 228 | if list == nil { 229 | return nil; 230 | } 231 | params: [dynamic]^Variable; 232 | 233 | named, anonymous: bool; 234 | for field, i in list.list { 235 | assert(field.type != nil); 236 | type := check_type(c, field.type); 237 | if len(field.names) > 0 { 238 | for name in field.names { 239 | if name.name == "" { 240 | check_error(name.pos, "invalid AST anonymous parameter"); 241 | } 242 | param := new_param(name.pos, c.pkg, name.name, type); 243 | declare_entity(c, c.scope, name, param); 244 | append(¶ms, param); 245 | } 246 | named = true; 247 | } else { 248 | param := new_param(field.type.pos, c.pkg, "", type); 249 | field.implicit = param; 250 | append(¶ms, param); 251 | anonymous = true; 252 | } 253 | } 254 | 255 | if named && anonymous { 256 | check_error(list.pos, "invalid AST containing both named and anonymous parameters"); 257 | } 258 | 259 | return params[:]; 260 | } 261 | -------------------------------------------------------------------------------- /src/frontend/types.odin: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import "core:strings" 4 | 5 | Standard_Sizes :: struct { 6 | word_size: i64, 7 | max_align: i64, 8 | } 9 | 10 | Type :: struct { 11 | variant: union { 12 | ^Basic, 13 | ^Array, 14 | ^Slice, 15 | ^Struct, 16 | ^Pointer, 17 | ^Tuple, 18 | ^Signature, 19 | ^Named, 20 | }, 21 | } 22 | 23 | Basic_Kind :: enum u8 { 24 | invalid, 25 | 26 | bool, 27 | 28 | i8, 29 | i16, 30 | i32, 31 | i64, 32 | isize, 33 | u8, 34 | u16, 35 | u32, 36 | u64, 37 | usize, 38 | 39 | rune, 40 | 41 | f32, 42 | f64, 43 | 44 | rawptr, 45 | string, 46 | 47 | untyped_nil, 48 | untyped_bool, 49 | untyped_int, 50 | untyped_float, 51 | untyped_rune, 52 | untyped_string, 53 | } 54 | 55 | Basic_Flag :: enum u8 { 56 | Boolean, 57 | Integer, 58 | Unsigned, 59 | Float, 60 | Pointer, 61 | String, 62 | Rune, 63 | Untyped, 64 | } 65 | 66 | Basic_Flags :: distinct bit_set[Basic_Flag; u32]; 67 | 68 | Basic_Flags_Numeric :: Basic_Flags{.Integer, .Float}; 69 | Basic_Flags_Ordered :: Basic_Flags{.Integer, .Float, .String, .Pointer, .Rune}; 70 | Basic_Flags_Ordered_Numeric :: Basic_Flags_Ordered & Basic_Flags_Numeric; 71 | Basic_Flags_Constant_Type :: Basic_Flags{.Boolean, .Integer, .Unsigned, .Float, .Pointer, .String, .Rune}; 72 | 73 | Basic :: struct { 74 | using base: Type, 75 | kind: Basic_Kind, 76 | flags: Basic_Flags, 77 | size: i64, 78 | align: i64, 79 | name: string, 80 | } 81 | 82 | 83 | btype := [Basic_Kind]Basic{ 84 | .invalid = {}, 85 | 86 | .bool = {{}, .bool, {.Boolean}, 1, 1, "bool"}, 87 | 88 | .i8 = {{}, .i8, {.Integer}, 1, 1, "i8"}, 89 | .i16 = {{}, .i16, {.Integer}, 2, 2, "i16"}, 90 | .i32 = {{}, .i32, {.Integer}, 4, 4, "i32"}, 91 | .i64 = {{}, .i64, {.Integer}, 8, 8, "i64"}, 92 | .isize = {{}, .isize, {.Integer}, -1, -1, "isize"}, 93 | .u8 = {{}, .u8, {.Integer, .Unsigned}, 1, 1, "u8"}, 94 | .u16 = {{}, .u16, {.Integer, .Unsigned}, 2, 2, "u16"}, 95 | .u32 = {{}, .u32, {.Integer, .Unsigned}, 4, 4, "u32"}, 96 | .u64 = {{}, .u64, {.Integer, .Unsigned}, 8, 8, "u64"}, 97 | .usize = {{}, .usize, {.Integer, .Unsigned}, -1, -1, "usize"}, 98 | 99 | .rune = {{}, .rune, {.Rune}, 4, 4, "rune"}, 100 | 101 | .f32 = {{}, .f32, {.Float}, 4, 4, "f32"}, 102 | .f64 = {{}, .f64, {.Float}, 8, 8, "f64"}, 103 | 104 | .rawptr = {{}, .rawptr, {.Pointer}, -1, -1, "rawptr"}, 105 | .string = {{}, .string, {.String}, -2, -1, "string"}, 106 | 107 | .untyped_nil = {{}, .untyped_nil, {.Untyped}, -1, -1, "untyped nil"}, 108 | .untyped_bool = {{}, .untyped_bool, {.Untyped, .Boolean}, -1, -1, "untyped bool"}, 109 | .untyped_int = {{}, .untyped_int, {.Untyped, .Integer}, -1, -1, "untyped int"}, 110 | .untyped_float = {{}, .untyped_float, {.Untyped, .Float}, -1, -1, "untyped float"}, 111 | .untyped_rune = {{}, .untyped_rune, {.Untyped, .Rune}, -1, -1, "untyped rune"}, 112 | .untyped_string = {{}, .untyped_string, {.Untyped, .String}, -1, -1, "untyped string"}, 113 | }; 114 | 115 | 116 | 117 | Array :: struct { 118 | using base: Type, 119 | len: i64, 120 | elem: ^Type, 121 | } 122 | 123 | Slice :: struct { 124 | using base: Type, 125 | elem: ^Type, 126 | } 127 | 128 | Struct :: struct { 129 | using base: Type, 130 | fields: []^Variable, 131 | offsets: []i64, 132 | } 133 | 134 | Pointer :: struct { 135 | using base: Type, 136 | elem: ^Type, 137 | } 138 | 139 | Tuple :: struct { 140 | using base: Type, 141 | vars: []^Variable, 142 | offsets: []i64, 143 | } 144 | 145 | Signature :: struct { 146 | using base: Type, 147 | scope: ^Scope, 148 | params: ^Tuple, 149 | results: ^Tuple, 150 | } 151 | 152 | Named_State :: enum { 153 | Unknown, 154 | Processing, 155 | Invalid, 156 | Valid, 157 | } 158 | 159 | Named :: struct { 160 | using base: Type, 161 | state: Named_State, 162 | entity: ^Type_Name, 163 | original: ^Type, 164 | underlying: ^Type, 165 | } 166 | 167 | new_type :: proc($T: typeid) -> ^T { 168 | t := new(T); 169 | t^.variant = t; 170 | return t; 171 | } 172 | 173 | new_tuple :: proc(vars: ..^Variable) -> ^Tuple { 174 | t := new_type(Tuple); 175 | t.vars = vars; 176 | return t; 177 | } 178 | 179 | new_pointer :: proc(elem: ^Type) -> ^Pointer { 180 | ptr := new_type(Pointer); 181 | ptr.elem = elem; 182 | return ptr; 183 | } 184 | 185 | tuple_len :: proc(t: ^Tuple) -> int { 186 | if t == nil { 187 | return 0; 188 | } 189 | return len(t.vars); 190 | } 191 | 192 | 193 | type_underlying :: proc(t: ^Type) -> ^Type { 194 | if t == nil { 195 | return nil; 196 | } 197 | if tname, ok := t.variant.(^Named); ok { 198 | return tname.underlying; 199 | } 200 | return t; 201 | } 202 | 203 | type_align_of :: proc(s: ^Standard_Sizes, t: ^Type) -> i64 { 204 | switch t in t.variant { 205 | case ^Basic: 206 | align := t.align; 207 | if align < 0 { 208 | align = -s.word_size; 209 | } 210 | return clamp(align, 1, s.max_align); 211 | 212 | case ^Array: 213 | return type_align_of(s, t.elem); 214 | 215 | case ^Slice, ^Pointer, ^Signature: 216 | return s.word_size; 217 | 218 | case ^Struct: 219 | max := i64(1); 220 | for f in t.fields { 221 | if a := type_align_of(s, f.type); a > max { 222 | max = a; 223 | } 224 | } 225 | return max; 226 | 227 | case ^Tuple: 228 | max := i64(1); 229 | for v in t.vars { 230 | if a := type_align_of(s, v.type); a > max { 231 | max = a; 232 | } 233 | } 234 | return max; 235 | 236 | case ^Named: 237 | return type_align_of(s, t.underlying); 238 | } 239 | return 1; 240 | } 241 | 242 | type_size_of :: proc(s: ^Standard_Sizes, t: ^Type) -> i64 { 243 | switch t in t.variant { 244 | case ^Basic: 245 | size := t.size; 246 | if size < 0 { 247 | size = -s.word_size; 248 | } 249 | return size; 250 | 251 | case ^Array: 252 | n := t.len; 253 | if n <= 0 { 254 | return 0; 255 | } 256 | a := type_align_of(s, t.elem); 257 | z := type_size_of(s, t.elem); 258 | return align_formula(z, a)*(n-1) + z; 259 | 260 | case ^Slice: 261 | return 2*s.word_size; 262 | case ^Pointer: 263 | return s.word_size; 264 | case ^Signature: 265 | return s.word_size; 266 | 267 | case ^Struct: 268 | n := len(t.fields); 269 | if n == 0 { 270 | return 0; 271 | } 272 | return t.offsets[n-1] + type_size_of(s, t.fields[n-1].type); 273 | 274 | case ^Tuple: 275 | n := len(t.vars); 276 | if n == 0 { 277 | return 0; 278 | } 279 | return t.offsets[n-1] + type_size_of(s, t.vars[n-1].type); 280 | 281 | case ^Named: 282 | return type_align_of(s, t.underlying); 283 | } 284 | 285 | // Catch All 286 | return s.word_size; 287 | } 288 | 289 | 290 | align_formula :: proc(size, align: i64) -> i64 { 291 | s := size + align - 1; 292 | return s - s%align; 293 | } 294 | 295 | default_type :: proc(t: ^Type) -> ^Type { 296 | if bt, ok := t.variant.(^Basic); ok { 297 | #partial switch bt.kind { 298 | case .untyped_bool: return &btype[.bool]; 299 | case .untyped_int: return &btype[.isize]; 300 | case .untyped_float: return &btype[.f64]; 301 | case .untyped_rune: return &btype[.rune]; 302 | case .untyped_string: return &btype[.string]; 303 | } 304 | } 305 | return t; 306 | } 307 | 308 | type_is_untyped :: proc(t: ^Type) -> bool { 309 | bt := type_underlying(t); 310 | if b, ok := bt.variant.(^Basic); ok { 311 | return .Untyped in b.flags; 312 | } 313 | return false; 314 | } 315 | 316 | type_is_typed :: proc(t: ^Type) -> bool { 317 | bt := type_underlying(t); 318 | if b, ok := bt.variant.(^Basic); ok { 319 | return .Untyped not_in b.flags; 320 | } 321 | return true; 322 | } 323 | 324 | 325 | type_has_nil :: proc(type: ^Type) -> bool { 326 | switch t in type_underlying(type).variant { 327 | case ^Basic: 328 | return t.kind == .rawptr || t.kind == .untyped_nil; 329 | case ^Array, ^Struct, ^Tuple: 330 | return false; 331 | case ^Slice, ^Pointer, ^Signature: 332 | return true; 333 | case ^Named: 334 | unreachable(); 335 | } 336 | return false; 337 | } 338 | 339 | type_is_comparable :: proc(type: ^Type) -> bool { 340 | switch t in type_underlying(type).variant { 341 | case ^Basic: 342 | return t.flags & Basic_Flags_Ordered != nil; 343 | case ^Array, ^Slice, ^Struct, ^Tuple: 344 | case ^Pointer, ^Signature: 345 | return true; 346 | case ^Named: 347 | unreachable(); 348 | } 349 | return false; 350 | } 351 | type_is_ordered :: proc(type: ^Type) -> bool { 352 | switch t in type_underlying(type).variant { 353 | case ^Basic: 354 | return t.flags & Basic_Flags_Ordered != nil; 355 | case ^Array, ^Slice, ^Struct, ^Tuple, ^Signature: 356 | return false; 357 | case ^Pointer: 358 | return true; 359 | case ^Named: 360 | unreachable(); 361 | } 362 | return false; 363 | } 364 | 365 | 366 | type_is_numeric :: proc(t: ^Type) -> bool { 367 | bt := type_underlying(t); 368 | if b, ok := bt.variant.(^Basic); ok { 369 | return b.flags & Basic_Flags_Numeric != nil; 370 | } 371 | return false; 372 | } 373 | 374 | type_is_integer :: proc(t: ^Type) -> bool { 375 | bt := type_underlying(t); 376 | if b, ok := bt.variant.(^Basic); ok { 377 | return .Integer in b.flags; 378 | } 379 | return false; 380 | } 381 | 382 | type_is_unsigned :: proc(t: ^Type) -> bool { 383 | bt := type_underlying(t); 384 | if b, ok := bt.variant.(^Basic); ok { 385 | return .Unsigned in b.flags; 386 | } 387 | return false; 388 | } 389 | 390 | type_is_boolean :: proc(t: ^Type) -> bool { 391 | bt := type_underlying(t); 392 | if b, ok := bt.variant.(^Basic); ok { 393 | return .Boolean in b.flags; 394 | } 395 | return false; 396 | } 397 | type_is_float :: proc(t: ^Type) -> bool { 398 | bt := type_underlying(t); 399 | if b, ok := bt.variant.(^Basic); ok { 400 | return .Float in b.flags; 401 | } 402 | return false; 403 | } 404 | type_is_string :: proc(t: ^Type) -> bool { 405 | bt := type_underlying(t); 406 | if b, ok := bt.variant.(^Basic); ok { 407 | return .String in b.flags; 408 | } 409 | return false; 410 | } 411 | type_is_pointer :: proc(t: ^Type) -> bool { 412 | bt := type_underlying(t); 413 | #partial switch b in bt.variant { 414 | case ^Basic: 415 | return .Pointer in b.flags; 416 | case ^Pointer: 417 | return true; 418 | } 419 | return false; 420 | } 421 | 422 | is_const_type :: proc(t: ^Type) -> bool { 423 | bt := type_underlying(t); 424 | #partial switch b in bt.variant { 425 | case ^Basic: 426 | return b.flags & Basic_Flags_Constant_Type != nil; 427 | } 428 | return false; 429 | } 430 | 431 | are_identical :: proc(x, y: ^Type) -> bool { 432 | if x == y { 433 | return true; 434 | } 435 | if x == nil || y == nil { 436 | return false; 437 | } 438 | switch x in x.variant { 439 | case ^Basic: 440 | if y, ok := y.variant.(^Basic); ok { 441 | return x.kind == y.kind; 442 | } 443 | case ^Array: 444 | if y, ok := y.variant.(^Array); ok { 445 | return (x.len == y.len) && are_identical(x.elem, y.elem); 446 | } 447 | case ^Slice: 448 | if y, ok := y.variant.(^Slice); ok { 449 | return are_identical(x.elem, y.elem); 450 | } 451 | case ^Struct: 452 | if y, ok := y.variant.(^Struct); ok { 453 | if len(x.fields) == len(y.fields) { 454 | for f, i in x.fields { 455 | g := y.fields[i]; 456 | if f.name != g.name || !are_identical(f.type, g.type) { 457 | return false; 458 | } 459 | } 460 | return true; 461 | } 462 | } 463 | case ^Pointer: 464 | if y, ok := y.variant.(^Pointer); ok { 465 | return are_identical(x.elem, y.elem); 466 | } 467 | case ^Tuple: 468 | if y, ok := y.variant.(^Tuple); ok { 469 | if len(x.vars) == len(y.vars) { 470 | for f, i in x.vars { 471 | g := y.vars[i]; 472 | if f.name != g.name || !are_identical(f.type, g.type) { 473 | return false; 474 | } 475 | } 476 | return true; 477 | } 478 | } 479 | case ^Signature: 480 | if y, ok := y.variant.(^Signature); ok { 481 | return are_identical(x.params, y.params) && are_identical(x.params, y.params); 482 | } 483 | case ^Named: 484 | if y, ok := y.variant.(^Named); ok { 485 | return x.entity == y.entity; 486 | } 487 | } 488 | 489 | 490 | return false; 491 | } 492 | 493 | 494 | -------------------------------------------------------------------------------- /src/main.odin: -------------------------------------------------------------------------------- 1 | package wasm 2 | 3 | import "core:fmt" 4 | import "core:os" 5 | import "core:strings" 6 | 7 | import "assembler" 8 | import "frontend" 9 | import "backend" 10 | 11 | _ :: fmt; 12 | 13 | main :: proc() { 14 | using frontend; 15 | path := "W:/Midgard/midgard/test.midgard"; 16 | src, ok := os.read_entire_file(path); 17 | defer delete(src); 18 | tok: Tokenizer; 19 | 20 | file := &File{ 21 | id = 1, 22 | fullpath = path, 23 | src = src, 24 | }; 25 | pkg := &Package{ 26 | id = 1, 27 | name = "midgard", 28 | fullpath = "W:/Midgard/midgard/", 29 | files = []^File{file}, 30 | }; 31 | file.pkg = pkg; 32 | init_error_system(); 33 | 34 | p := Parser{}; 35 | p.err = default_error_handler; 36 | parse_file(&p, file); 37 | 38 | if frontend.total_error_count != 0 { 39 | fmt.eprintln("[fail]"); 40 | return; 41 | } 42 | 43 | 44 | checker := &Checker{}; 45 | check_pkgs(checker, {pkg}); 46 | if frontend.total_error_count != 0 { 47 | fmt.eprintln("[fail]"); 48 | return; 49 | } 50 | 51 | module: backend.Module; 52 | 53 | backend.generate_wasm(&module, checker); 54 | 55 | write_html_file(module.assembler.emitter.binary_data[:]); 56 | os.write_entire_file("test.wasm", module.assembler.emitter.binary_data[:]); 57 | 58 | fmt.eprintln("[done]"); 59 | } 60 | 61 | assemble :: proc() { 62 | using assembler; 63 | a := &Assembler{}; 64 | 65 | env_print := import_function(a, 66 | "env", "print", 67 | signature(a, {}, .void)); 68 | 69 | 70 | add_memory(a, 2*PAGE_SIZE, "memory"); 71 | 72 | __heap_base := i32(PAGE_SIZE); 73 | 74 | add_global(a, { 75 | type = .i32, 76 | expr = __heap_base, 77 | name = "__heap_base", 78 | kind = .Export, 79 | }); 80 | add_global(a, { 81 | type = .i32, 82 | expr = i32(1<<10), 83 | name = "__data_end", 84 | kind = .Export, 85 | }); 86 | 87 | { 88 | code := create_function(a, { 89 | name = "main", 90 | sig = signature(a, {}, .void), 91 | kind = .Export, 92 | }); 93 | 94 | emit_u32(code, 0); // Locals 95 | 96 | emit_call(code, env_print); 97 | 98 | emit_op(code, .End); 99 | } 100 | 101 | 102 | generate_assembly(a); 103 | 104 | // disassemble_byte_code(a.emitter.binary_data[:]); 105 | 106 | write_html_file(a.emitter.binary_data[:]); 107 | os.write_entire_file("test.wasm", a.emitter.binary_data[:]); 108 | } 109 | 110 | write_html_file :: proc(binary_data: []byte) { 111 | b := strings.make_builder(); 112 | defer strings.destroy_builder(&b); 113 | defer os.write_entire_file("test.html", b.buf[:]); 114 | 115 | strings.write_string(&b, 116 | ` 117 | 118 | 119 | WASM Test 120 | 128 | 129 | 167 | 168 | 169 | `); 170 | strings.write_string(&b, ``); 171 | } 172 | -------------------------------------------------------------------------------- /test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WASM Test 5 | 13 | 14 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /test.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gingerBill/Midgard/3d359e867e044119ed08859d25dda85213d6fa75/test.wasm --------------------------------------------------------------------------------