| author | |
| committer | |
| log | e7ab2bc5534a53c57c900618ec2411542dc50f69 |
| tree | 42c572bf7414f59a98cd40a37e7d2f5d94955084 |
| parent | 7903a758a44d1a253f17a4a2383f36b5fdad8545 |
| parent | c721354b73508ec53bf72d8e7fb304147676625d |
4 files changed, 146 insertions(+), 57 deletions(-)
src/zig_llvm.cpp+8-27| ... | ... | @@ -43,31 +43,8 @@ |
| 43 | 43 | |
| 44 | 44 | #include <stdlib.h> |
| 45 | 45 | |
| 46 | #if defined(_MSC_VER) | |
| 47 | #define ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict) | |
| 48 | #else | |
| 49 | #define ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__)) | |
| 50 | #endif | |
| 51 | ||
| 52 | 46 | using namespace llvm; |
| 53 | 47 | |
| 54 | template<typename T, typename... Args> | |
| 55 | ATTRIBUTE_RETURNS_NOALIAS static inline T * create(Args... args) { | |
| 56 | T * ptr = reinterpret_cast<T*>(malloc(sizeof(T))); | |
| 57 | if (ptr == nullptr) | |
| 58 | return nullptr; | |
| 59 | new (ptr) T(args...); | |
| 60 | return ptr; | |
| 61 | } | |
| 62 | ||
| 63 | template<typename T> | |
| 64 | static inline void destroy(T * ptr) { | |
| 65 | if (ptr != nullptr) { | |
| 66 | ptr[0].~T(); | |
| 67 | } | |
| 68 | free(ptr); | |
| 69 | } | |
| 70 | ||
| 71 | 48 | void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R) { |
| 72 | 49 | initializeLoopStrengthReducePass(*unwrap(R)); |
| 73 | 50 | } |
| ... | ... | @@ -116,7 +93,11 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 116 | 93 | |
| 117 | 94 | Module* module = unwrap(module_ref); |
| 118 | 95 | |
| 119 | PassManagerBuilder *PMBuilder = create<PassManagerBuilder>(); | |
| 96 | PassManagerBuilder *PMBuilder = new(std::nothrow) PassManagerBuilder(); | |
| 97 | if (PMBuilder == nullptr) { | |
| 98 | *error_message = strdup("memory allocation failure"); | |
| 99 | return true; | |
| 100 | } | |
| 120 | 101 | PMBuilder->OptLevel = target_machine->getOptLevel(); |
| 121 | 102 | PMBuilder->SizeLevel = 0; |
| 122 | 103 | |
| ... | ... | @@ -150,7 +131,8 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 150 | 131 | |
| 151 | 132 | // Set up the per-function pass manager. |
| 152 | 133 | legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module); |
| 153 | FPM.add(create<TargetLibraryInfoWrapperPass>(tlii)); | |
| 134 | auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii); | |
| 135 | FPM.add(tliwp); | |
| 154 | 136 | FPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); |
| 155 | 137 | if (assertions_on) { |
| 156 | 138 | FPM.add(createVerifierPass()); |
| ... | ... | @@ -446,10 +428,9 @@ unsigned ZigLLVMTag_DW_union_type(void) { |
| 446 | 428 | } |
| 447 | 429 | |
| 448 | 430 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) { |
| 449 | DIBuilder *di_builder = reinterpret_cast<DIBuilder*>(malloc(sizeof(DIBuilder))); | |
| 431 | DIBuilder *di_builder = new(std::nothrow) DIBuilder(*unwrap(module), allow_unresolved); | |
| 450 | 432 | if (di_builder == nullptr) |
| 451 | 433 | return nullptr; |
| 452 | new (di_builder) DIBuilder(*unwrap(module), allow_unresolved); | |
| 453 | 434 | return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder); |
| 454 | 435 | } |
| 455 | 436 |
std/zig/ast.zig+17-15| ... | ... | @@ -18,6 +18,7 @@ pub const Node = struct { |
| 18 | 18 | PrefixOp, |
| 19 | 19 | IntegerLiteral, |
| 20 | 20 | FloatLiteral, |
| 21 | BuiltinCall, | |
| 21 | 22 | }; |
| 22 | 23 | |
| 23 | 24 | pub fn iterate(base: &Node, index: usize) ?&Node { |
| ... | ... | @@ -32,21 +33,7 @@ pub const Node = struct { |
| 32 | 33 | Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index), |
| 33 | 34 | Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index), |
| 34 | 35 | Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index), |
| 35 | }; | |
| 36 | } | |
| 37 | ||
| 38 | pub fn destroy(base: &Node, allocator: &mem.Allocator) void { | |
| 39 | return switch (base.id) { | |
| 40 | Id.Root => allocator.destroy(@fieldParentPtr(NodeRoot, "base", base)), | |
| 41 | Id.VarDecl => allocator.destroy(@fieldParentPtr(NodeVarDecl, "base", base)), | |
| 42 | Id.Identifier => allocator.destroy(@fieldParentPtr(NodeIdentifier, "base", base)), | |
| 43 | Id.FnProto => allocator.destroy(@fieldParentPtr(NodeFnProto, "base", base)), | |
| 44 | Id.ParamDecl => allocator.destroy(@fieldParentPtr(NodeParamDecl, "base", base)), | |
| 45 | Id.Block => allocator.destroy(@fieldParentPtr(NodeBlock, "base", base)), | |
| 46 | Id.InfixOp => allocator.destroy(@fieldParentPtr(NodeInfixOp, "base", base)), | |
| 47 | Id.PrefixOp => allocator.destroy(@fieldParentPtr(NodePrefixOp, "base", base)), | |
| 48 | Id.IntegerLiteral => allocator.destroy(@fieldParentPtr(NodeIntegerLiteral, "base", base)), | |
| 49 | Id.FloatLiteral => allocator.destroy(@fieldParentPtr(NodeFloatLiteral, "base", base)), | |
| 36 | Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index), | |
| 50 | 37 | }; |
| 51 | 38 | } |
| 52 | 39 | }; |
| ... | ... | @@ -269,3 +256,18 @@ pub const NodeFloatLiteral = struct { |
| 269 | 256 | return null; |
| 270 | 257 | } |
| 271 | 258 | }; |
| 259 | ||
| 260 | pub const NodeBuiltinCall = struct { | |
| 261 | base: Node, | |
| 262 | builtin_token: Token, | |
| 263 | params: ArrayList(&Node), | |
| 264 | ||
| 265 | pub fn iterate(self: &NodeBuiltinCall, index: usize) ?&Node { | |
| 266 | var i = index; | |
| 267 | ||
| 268 | if (i < self.params.len) return self.params.at(i); | |
| 269 | i -= self.params.len; | |
| 270 | ||
| 271 | return null; | |
| 272 | } | |
| 273 | }; |
std/zig/parser.zig+2-1| ... | ... | @@ -95,7 +95,8 @@ pub const Parser = struct { |
| 95 | 95 | }; |
| 96 | 96 | |
| 97 | 97 | /// Returns an AST tree, allocated with the parser's allocator. |
| 98 | /// Result should be freed with `freeAst` when done. | |
| 98 | /// Result should be freed with tree.deinit() when there are | |
| 99 | /// no more references to any AST nodes of the tree. | |
| 99 | 100 | pub fn parse(self: &Parser) !Tree { |
| 100 | 101 | var stack = self.initUtilityArrayList(State); |
| 101 | 102 | defer self.deinitUtilityArrayList(stack); |
std/zig/tokenizer.zig+119-14| ... | ... | @@ -68,9 +68,12 @@ pub const Token = struct { |
| 68 | 68 | Invalid, |
| 69 | 69 | Identifier, |
| 70 | 70 | StringLiteral: StrLitKind, |
| 71 | StringIdentifier, | |
| 71 | 72 | Eof, |
| 72 | 73 | Builtin, |
| 73 | 74 | Bang, |
| 75 | Pipe, | |
| 76 | PipeEqual, | |
| 74 | 77 | Equal, |
| 75 | 78 | EqualEqual, |
| 76 | 79 | BangEqual, |
| ... | ... | @@ -192,6 +195,7 @@ pub const Tokenizer = struct { |
| 192 | 195 | StringLiteralBackslash, |
| 193 | 196 | Equal, |
| 194 | 197 | Bang, |
| 198 | Pipe, | |
| 195 | 199 | Minus, |
| 196 | 200 | Slash, |
| 197 | 201 | LineComment, |
| ... | ... | @@ -205,6 +209,7 @@ pub const Tokenizer = struct { |
| 205 | 209 | Ampersand, |
| 206 | 210 | Period, |
| 207 | 211 | Period2, |
| 212 | SawAtSign, | |
| 208 | 213 | }; |
| 209 | 214 | |
| 210 | 215 | pub fn next(self: &Tokenizer) Token { |
| ... | ... | @@ -238,8 +243,7 @@ pub const Tokenizer = struct { |
| 238 | 243 | result.id = Token.Id.Identifier; |
| 239 | 244 | }, |
| 240 | 245 | '@' => { |
| 241 | state = State.Builtin; | |
| 242 | result.id = Token.Id.Builtin; | |
| 246 | state = State.SawAtSign; | |
| 243 | 247 | }, |
| 244 | 248 | '=' => { |
| 245 | 249 | state = State.Equal; |
| ... | ... | @@ -247,6 +251,9 @@ pub const Tokenizer = struct { |
| 247 | 251 | '!' => { |
| 248 | 252 | state = State.Bang; |
| 249 | 253 | }, |
| 254 | '|' => { | |
| 255 | state = State.Pipe; | |
| 256 | }, | |
| 250 | 257 | '(' => { |
| 251 | 258 | result.id = Token.Id.LParen; |
| 252 | 259 | self.index += 1; |
| ... | ... | @@ -313,6 +320,20 @@ pub const Tokenizer = struct { |
| 313 | 320 | break; |
| 314 | 321 | }, |
| 315 | 322 | }, |
| 323 | ||
| 324 | State.SawAtSign => switch (c) { | |
| 325 | '"' => { | |
| 326 | result.id = Token.Id.StringIdentifier; | |
| 327 | state = State.StringLiteral; | |
| 328 | }, | |
| 329 | else => { | |
| 330 | // reinterpret as a builtin | |
| 331 | self.index -= 1; | |
| 332 | state = State.Builtin; | |
| 333 | result.id = Token.Id.Builtin; | |
| 334 | }, | |
| 335 | }, | |
| 336 | ||
| 316 | 337 | State.Ampersand => switch (c) { |
| 317 | 338 | '=' => { |
| 318 | 339 | result.id = Token.Id.AmpersandEqual; |
| ... | ... | @@ -379,6 +400,18 @@ pub const Tokenizer = struct { |
| 379 | 400 | }, |
| 380 | 401 | }, |
| 381 | 402 | |
| 403 | State.Pipe => switch (c) { | |
| 404 | '=' => { | |
| 405 | result.id = Token.Id.PipeEqual; | |
| 406 | self.index += 1; | |
| 407 | break; | |
| 408 | }, | |
| 409 | else => { | |
| 410 | result.id = Token.Id.Pipe; | |
| 411 | break; | |
| 412 | }, | |
| 413 | }, | |
| 414 | ||
| 382 | 415 | State.Equal => switch (c) { |
| 383 | 416 | '=' => { |
| 384 | 417 | result.id = Token.Id.EqualEqual; |
| ... | ... | @@ -510,9 +543,62 @@ pub const Tokenizer = struct { |
| 510 | 543 | else => break, |
| 511 | 544 | }, |
| 512 | 545 | } |
| 513 | } | |
| 514 | result.end = self.index; | |
| 546 | } else if (self.index == self.buffer.len) { | |
| 547 | switch (state) { | |
| 548 | State.Start, | |
| 549 | State.C, | |
| 550 | State.IntegerLiteral, | |
| 551 | State.IntegerLiteralWithRadix, | |
| 552 | State.FloatFraction, | |
| 553 | State.FloatExponentNumber, | |
| 554 | State.StringLiteral, // find this error later | |
| 555 | State.Builtin => {}, | |
| 556 | ||
| 557 | State.Identifier => { | |
| 558 | if (Token.getKeyword(self.buffer[result.start..self.index])) |id| { | |
| 559 | result.id = id; | |
| 560 | } | |
| 561 | }, | |
| 562 | State.LineComment => { | |
| 563 | result.id = Token.Id.Eof; | |
| 564 | }, | |
| 565 | ||
| 566 | State.NumberDot, | |
| 567 | State.FloatExponentUnsigned, | |
| 568 | State.SawAtSign, | |
| 569 | State.StringLiteralBackslash => { | |
| 570 | result.id = Token.Id.Invalid; | |
| 571 | }, | |
| 515 | 572 | |
| 573 | State.Equal => { | |
| 574 | result.id = Token.Id.Equal; | |
| 575 | }, | |
| 576 | State.Bang => { | |
| 577 | result.id = Token.Id.Bang; | |
| 578 | }, | |
| 579 | State.Minus => { | |
| 580 | result.id = Token.Id.Minus; | |
| 581 | }, | |
| 582 | State.Slash => { | |
| 583 | result.id = Token.Id.Slash; | |
| 584 | }, | |
| 585 | State.Zero => { | |
| 586 | result.id = Token.Id.IntegerLiteral; | |
| 587 | }, | |
| 588 | State.Ampersand => { | |
| 589 | result.id = Token.Id.Ampersand; | |
| 590 | }, | |
| 591 | State.Period => { | |
| 592 | result.id = Token.Id.Period; | |
| 593 | }, | |
| 594 | State.Period2 => { | |
| 595 | result.id = Token.Id.Ellipsis2; | |
| 596 | }, | |
| 597 | State.Pipe => { | |
| 598 | result.id = Token.Id.Pipe; | |
| 599 | }, | |
| 600 | } | |
| 601 | } | |
| 516 | 602 | if (result.id == Token.Id.Eof) { |
| 517 | 603 | if (self.pending_invalid_token) |token| { |
| 518 | 604 | self.pending_invalid_token = null; |
| ... | ... | @@ -520,6 +606,7 @@ pub const Tokenizer = struct { |
| 520 | 606 | } |
| 521 | 607 | } |
| 522 | 608 | |
| 609 | result.end = self.index; | |
| 523 | 610 | return result; |
| 524 | 611 | } |
| 525 | 612 | |
| ... | ... | @@ -551,7 +638,7 @@ pub const Tokenizer = struct { |
| 551 | 638 | } else { |
| 552 | 639 | // check utf8-encoded character. |
| 553 | 640 | const length = std.unicode.utf8ByteSequenceLength(c0) catch return 1; |
| 554 | if (self.index + length >= self.buffer.len) { | |
| 641 | if (self.index + length > self.buffer.len) { | |
| 555 | 642 | return u3(self.buffer.len - self.index); |
| 556 | 643 | } |
| 557 | 644 | const bytes = self.buffer[self.index..self.index + length]; |
| ... | ... | @@ -632,15 +719,32 @@ test "tokenizer - illegal unicode codepoints" { |
| 632 | 719 | testTokenize("//\xe2\x80\xaa", []Token.Id{}); |
| 633 | 720 | } |
| 634 | 721 | |
| 722 | test "tokenizer - string identifier and builtin fns" { | |
| 723 | testTokenize( | |
| 724 | \\const @"if" = @import("std"); | |
| 725 | , | |
| 726 | []Token.Id{ | |
| 727 | Token.Id.Keyword_const, | |
| 728 | Token.Id.StringIdentifier, | |
| 729 | Token.Id.Equal, | |
| 730 | Token.Id.Builtin, | |
| 731 | Token.Id.LParen, | |
| 732 | Token.Id {.StringLiteral = Token.StrLitKind.Normal}, | |
| 733 | Token.Id.RParen, | |
| 734 | Token.Id.Semicolon, | |
| 735 | } | |
| 736 | ); | |
| 737 | } | |
| 738 | ||
| 739 | test "tokenizer - pipe and then invalid" { | |
| 740 | testTokenize("||=", []Token.Id{ | |
| 741 | Token.Id.Pipe, | |
| 742 | Token.Id.PipeEqual, | |
| 743 | }); | |
| 744 | } | |
| 745 | ||
| 635 | 746 | fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void { |
| 636 | // (test authors, just make this bigger if you need it) | |
| 637 | var padded_source: [0x100]u8 = undefined; | |
| 638 | std.mem.copy(u8, padded_source[0..source.len], source); | |
| 639 | padded_source[source.len + 0] = '\n'; | |
| 640 | padded_source[source.len + 1] = '\n'; | |
| 641 | padded_source[source.len + 2] = '\n'; | |
| 642 | ||
| 643 | var tokenizer = Tokenizer.init(padded_source[0..source.len + 3]); | |
| 747 | var tokenizer = Tokenizer.init(source); | |
| 644 | 748 | for (expected_tokens) |expected_token_id| { |
| 645 | 749 | const token = tokenizer.next(); |
| 646 | 750 | std.debug.assert(@TagType(Token.Id)(token.id) == @TagType(Token.Id)(expected_token_id)); |
| ... | ... | @@ -651,5 +755,6 @@ fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void { |
| 651 | 755 | else => {}, |
| 652 | 756 | } |
| 653 | 757 | } |
| 654 | std.debug.assert(tokenizer.next().id == Token.Id.Eof); | |
| 758 | const last_token = tokenizer.next(); | |
| 759 | std.debug.assert(last_token.id == Token.Id.Eof); | |
| 655 | 760 | } |