Update to GCC 15.1
This commit is contained in:
		
							
								
								
									
										4
									
								
								Rakefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Rakefile
									
									
									
									
									
								
							| @@ -8,8 +8,7 @@ require 'rake/clean' | |||||||
| require_relative 'tools/support' | require_relative 'tools/support' | ||||||
|  |  | ||||||
| # Dependencies. | # Dependencies. | ||||||
| GCC_VERSION = "14.2.0" | GCC_VERSION = "15.1.0" | ||||||
| GCC_PATCH = 'https://raw.githubusercontent.com/Homebrew/formula-patches/f30c309442a60cfb926e780eae5d70571f8ab2cb/gcc/gcc-14.2.0-r2.diff' |  | ||||||
|  |  | ||||||
| # Paths. | # Paths. | ||||||
| HOST_GCC = TMP + 'host/gcc' | HOST_GCC = TMP + 'host/gcc' | ||||||
| @@ -34,7 +33,6 @@ namespace :boot do | |||||||
|     frontend_link = source_directory + 'gcc' |     frontend_link = source_directory + 'gcc' | ||||||
|  |  | ||||||
|     download_and_pipe url, source_directory.dirname, ['tar', '-Jxv'] |     download_and_pipe url, source_directory.dirname, ['tar', '-Jxv'] | ||||||
|     download_and_pipe URI.parse(GCC_PATCH), source_directory, ['patch', '-p1'] |  | ||||||
|  |  | ||||||
|     sh 'contrib/download_prerequisites', chdir: source_directory.to_path |     sh 'contrib/download_prerequisites', chdir: source_directory.to_path | ||||||
|     File.symlink Pathname.new('.').relative_path_from(frontend_link), (frontend_link + 'elna') |     File.symlink Pathname.new('.').relative_path_from(frontend_link), (frontend_link + 'elna') | ||||||
|   | |||||||
| @@ -211,9 +211,9 @@ procedure_heading: | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| procedure_definition: | procedure_definition: | ||||||
|     "proc" identifier_definition procedure_heading ";" block |     "proc" identifier_definition procedure_heading block | ||||||
|         { |         { | ||||||
|             $$ = new boot::procedure_definition(boot::make_position(@1), std::move($2), $3.second, $5); |             $$ = new boot::procedure_definition(boot::make_position(@1), std::move($2), $3.second, $4); | ||||||
|             std::swap($3.first, $$->parameter_names); |             std::swap($3.first, $$->parameter_names); | ||||||
|         } |         } | ||||||
|     | "proc" identifier_definition procedure_heading ";" "extern" |     | "proc" identifier_definition procedure_heading ";" "extern" | ||||||
|   | |||||||
							
								
								
									
										129
									
								
								source.elna
									
									
									
									
									
								
							
							
						
						
									
										129
									
								
								source.elna
									
									
									
									
									
								
							| @@ -19,12 +19,12 @@ type | |||||||
|     _extern, |     _extern, | ||||||
|     _const, |     _const, | ||||||
|     _var, |     _var, | ||||||
|     array, |     _case, | ||||||
|     _of, |     _of, | ||||||
|     _type, |     _type, | ||||||
|     _record, |     _record, | ||||||
|     _union, |     _union, | ||||||
|     pointer, |     pipe, | ||||||
|     to, |     to, | ||||||
|     boolean, |     boolean, | ||||||
|     _nil, |     _nil, | ||||||
| @@ -64,7 +64,8 @@ type | |||||||
|     string, |     string, | ||||||
|     _defer, |     _defer, | ||||||
|     exclamation, |     exclamation, | ||||||
|     arrow |     arrow, | ||||||
|  | 	trait | ||||||
|   ) |   ) | ||||||
|   Position* = record |   Position* = record | ||||||
|     line: Word; |     line: Word; | ||||||
| @@ -140,22 +141,22 @@ proc exit(code: Int) -> !; extern | |||||||
| (* | (* | ||||||
|   Standard procedures. |   Standard procedures. | ||||||
| *) | *) | ||||||
| proc reallocarray(ptr: ^Byte, n: Word, size: Word) -> ^Byte; | proc reallocarray(ptr: ^Byte, n: Word, size: Word) -> ^Byte | ||||||
| begin | begin | ||||||
|   return realloc(ptr, n * size) |   return realloc(ptr, n * size) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc write_s(value: String); | proc write_s(value: String) | ||||||
| begin | begin | ||||||
|   write(0, cast(value.ptr: ^Byte), cast(value.length: Int)) |   write(0, cast(value.ptr: ^Byte), cast(value.length: Int)) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc write_z(value: ^Char); | proc write_z(value: ^Char) | ||||||
| begin | begin | ||||||
|   write(0, cast(value: ^Byte), cast(strlen(value): Int)) |   write(0, cast(value: ^Byte), cast(strlen(value): Int)) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc write_b(value: Bool); | proc write_b(value: Bool) | ||||||
| begin | begin | ||||||
|   if value then |   if value then | ||||||
|     write_s("true") |     write_s("true") | ||||||
| @@ -164,12 +165,12 @@ begin | |||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
| proc write_c(value: Char); | proc write_c(value: Char) | ||||||
| begin | begin | ||||||
|   write(0, cast(@value: ^Byte), 1) |   write(0, cast(@value: ^Byte), 1) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc write_i(value: Int); | proc write_i(value: Int) | ||||||
| var | var | ||||||
|   digit: Int |   digit: Int | ||||||
|   n: Word |   n: Word | ||||||
| @@ -193,42 +194,42 @@ begin | |||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
| proc write_u(value: Word); | proc write_u(value: Word) | ||||||
| begin | begin | ||||||
|   write_i(cast(value: Int)) |   write_i(cast(value: Int)) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc is_digit(c: Char) -> Bool; | proc is_digit(c: Char) -> Bool | ||||||
| begin | begin | ||||||
|   return cast(c: Int) >= cast('0': Int) & cast(c: Int) <= cast('9': Int) |   return cast(c: Int) >= cast('0': Int) & cast(c: Int) <= cast('9': Int) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc is_alpha(c: Char) -> Bool; | proc is_alpha(c: Char) -> Bool | ||||||
| begin | begin | ||||||
|   return cast(c: Int) >= cast('A': Int) & cast(c: Int) <= cast('z': Int) |   return cast(c: Int) >= cast('A': Int) & cast(c: Int) <= cast('z': Int) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc is_alnum(c: Char) -> Bool; | proc is_alnum(c: Char) -> Bool | ||||||
| begin | begin | ||||||
|   return is_digit(c) or is_alpha(c) |   return is_digit(c) or is_alpha(c) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc is_space(c: Char) -> Bool; | proc is_space(c: Char) -> Bool | ||||||
| begin | begin | ||||||
|   return c = ' ' or c = '\n' or c = '\t' |   return c = ' ' or c = '\n' or c = '\t' | ||||||
| end | end | ||||||
|  |  | ||||||
| proc substring(string: String, start: Word, count: Word) -> String; | proc substring(string: String, start: Word, count: Word) -> String | ||||||
| begin | begin | ||||||
|   return String(string.ptr + start, count) |   return String(string.ptr + start, count) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc open_substring(string: String, start: Word) -> String; | proc open_substring(string: String, start: Word) -> String | ||||||
| begin | begin | ||||||
|   return substring(string, start, string.length - start) |   return substring(string, start, string.length - start) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc string_dup(origin: String) -> String; | proc string_dup(origin: String) -> String | ||||||
| var | var | ||||||
|   copy: ^Char |   copy: ^Char | ||||||
| begin | begin | ||||||
| @@ -238,7 +239,7 @@ begin | |||||||
|   return String(copy, origin.length) |   return String(copy, origin.length) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc string_buffer_new() -> StringBuffer; | proc string_buffer_new() -> StringBuffer | ||||||
| var | var | ||||||
|   result: StringBuffer |   result: StringBuffer | ||||||
| begin | begin | ||||||
| @@ -249,7 +250,7 @@ begin | |||||||
|   return result |   return result | ||||||
| end | end | ||||||
|  |  | ||||||
| proc string_buffer_push(buffer: ^StringBuffer, char: Char); | proc string_buffer_push(buffer: ^StringBuffer, char: Char) | ||||||
| begin | begin | ||||||
|   if buffer^.size >= buffer^.capacity then |   if buffer^.size >= buffer^.capacity then | ||||||
|     buffer^.capacity := buffer^.capacity + 1024u; |     buffer^.capacity := buffer^.capacity + 1024u; | ||||||
| @@ -259,12 +260,12 @@ begin | |||||||
|   buffer^.size := buffer^.size + 1u |   buffer^.size := buffer^.size + 1u | ||||||
| end | end | ||||||
|  |  | ||||||
| proc string_buffer_pop(buffer: ^StringBuffer, count: Word); | proc string_buffer_pop(buffer: ^StringBuffer, count: Word) | ||||||
| begin | begin | ||||||
|   buffer^.size := buffer^.size - count |   buffer^.size := buffer^.size - count | ||||||
| end | end | ||||||
|  |  | ||||||
| proc string_buffer_clear(buffer: ^StringBuffer) -> String; | proc string_buffer_clear(buffer: ^StringBuffer) -> String | ||||||
| var | var | ||||||
|   result: String |   result: String | ||||||
| begin | begin | ||||||
| @@ -277,12 +278,12 @@ end | |||||||
|   End of standard procedures. |   End of standard procedures. | ||||||
| *) | *) | ||||||
|  |  | ||||||
| proc make_position() -> Position; | proc make_position() -> Position | ||||||
| begin | begin | ||||||
|   return Position(1u, 1u) |   return Position(1u, 1u) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc read_source(filename: ^Char) -> ^SourceFile; | proc read_source(filename: ^Char) -> ^SourceFile | ||||||
| var | var | ||||||
|   result: ^SourceFile |   result: ^SourceFile | ||||||
|   file_handle: ^FILE |   file_handle: ^FILE | ||||||
| @@ -298,7 +299,7 @@ begin | |||||||
|   return result |   return result | ||||||
| end | end | ||||||
|  |  | ||||||
| proc escape_char(escape: Char, result: ^Char) -> Bool; | proc escape_char(escape: Char, result: ^Char) -> Bool | ||||||
| var | var | ||||||
|   successful: Bool |   successful: Bool | ||||||
| begin | begin | ||||||
| @@ -344,7 +345,7 @@ begin | |||||||
|   return successful |   return successful | ||||||
| end | end | ||||||
|  |  | ||||||
| proc source_file_empty(source_input: ^Byte) -> Bool; | proc source_file_empty(source_input: ^Byte) -> Bool | ||||||
| var | var | ||||||
|   source_file: ^SourceFile |   source_file: ^SourceFile | ||||||
| begin | begin | ||||||
| @@ -358,7 +359,7 @@ begin | |||||||
|   return source_file^.size = 0u |   return source_file^.size = 0u | ||||||
| end | end | ||||||
|  |  | ||||||
| proc source_file_head(source_input: ^Byte) -> Char; | proc source_file_head(source_input: ^Byte) -> Char | ||||||
| var | var | ||||||
|   source_file: ^SourceFile |   source_file: ^SourceFile | ||||||
| begin | begin | ||||||
| @@ -367,7 +368,7 @@ begin | |||||||
|   return source_file^.buffer[source_file^.index] |   return source_file^.buffer[source_file^.index] | ||||||
| end | end | ||||||
|  |  | ||||||
| proc source_file_advance(source_input: ^Byte); | proc source_file_advance(source_input: ^Byte) | ||||||
| var | var | ||||||
|   source_file: ^SourceFile |   source_file: ^SourceFile | ||||||
| begin | begin | ||||||
| @@ -376,34 +377,34 @@ begin | |||||||
|   source_file^.index := source_file^.index + 1u |   source_file^.index := source_file^.index + 1u | ||||||
| end | end | ||||||
|  |  | ||||||
| proc source_code_empty(source_code: ^SourceCode) -> Bool; | proc source_code_empty(source_code: ^SourceCode) -> Bool | ||||||
| begin | begin | ||||||
|   return source_code^.empty(source_code^.input) |   return source_code^.empty(source_code^.input) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc source_code_head(source_code: SourceCode) -> Char; | proc source_code_head(source_code: SourceCode) -> Char | ||||||
| begin | begin | ||||||
|   return source_code.head(source_code.input) |   return source_code.head(source_code.input) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc source_code_advance(source_code: ^SourceCode); | proc source_code_advance(source_code: ^SourceCode) | ||||||
| begin | begin | ||||||
|   source_code^.advance(source_code^.input); |   source_code^.advance(source_code^.input); | ||||||
|   source_code^.position.column := source_code^.position.column |   source_code^.position.column := source_code^.position.column | ||||||
| end | end | ||||||
|  |  | ||||||
| proc source_code_break(source_code: ^SourceCode); | proc source_code_break(source_code: ^SourceCode) | ||||||
| begin | begin | ||||||
|   source_code^.position.line := source_code^.position.line + 1u; |   source_code^.position.line := source_code^.position.line + 1u; | ||||||
|   source_code^.position.column := 0u |   source_code^.position.column := 0u | ||||||
| end | end | ||||||
|  |  | ||||||
| proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool; | proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool | ||||||
| begin | begin | ||||||
|   return ~source_code_empty(source_code) & source_code_head(source_code^) = expected |   return ~source_code_empty(source_code) & source_code_head(source_code^) = expected | ||||||
| end | end | ||||||
|  |  | ||||||
| proc skip_spaces(source_code: ^SourceCode); | proc skip_spaces(source_code: ^SourceCode) | ||||||
| var | var | ||||||
|   current: Char |   current: Char | ||||||
| begin | begin | ||||||
| @@ -419,12 +420,12 @@ begin | |||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
| proc is_ident(char: Char) -> Bool; | proc is_ident(char: Char) -> Bool | ||||||
| begin | begin | ||||||
|   return is_alnum(char) or char = '_' |   return is_alnum(char) or char = '_' | ||||||
| end | end | ||||||
|  |  | ||||||
| proc lex_identifier(source_code: ^SourceCode, token_content: ^StringBuffer); | proc lex_identifier(source_code: ^SourceCode, token_content: ^StringBuffer) | ||||||
| var | var | ||||||
|   content_length: Word |   content_length: Word | ||||||
| begin | begin | ||||||
| @@ -434,7 +435,7 @@ begin | |||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
| proc lex_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool; | proc lex_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool | ||||||
| var | var | ||||||
|   trailing: Word |   trailing: Word | ||||||
| begin | begin | ||||||
| @@ -457,7 +458,7 @@ begin | |||||||
|   return trailing = 2u |   return trailing = 2u | ||||||
| end | end | ||||||
|  |  | ||||||
| proc lex_character(source_code: ^SourceCode, token_content: ^Char) -> Bool; | proc lex_character(source_code: ^SourceCode, token_content: ^Char) -> Bool | ||||||
| var | var | ||||||
|   successful: Bool |   successful: Bool | ||||||
| begin | begin | ||||||
| @@ -479,7 +480,7 @@ begin | |||||||
|   return successful |   return successful | ||||||
| end | end | ||||||
|  |  | ||||||
| proc lex_string(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool; | proc lex_string(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool | ||||||
| var | var | ||||||
|   token_end, constructed_string: ^Char |   token_end, constructed_string: ^Char | ||||||
|   token_length: Word |   token_length: Word | ||||||
| @@ -504,7 +505,7 @@ begin | |||||||
|   return is_valid |   return is_valid | ||||||
| end | end | ||||||
|  |  | ||||||
| proc lex_number(source_code: ^SourceCode, token_content: ^Int); | proc lex_number(source_code: ^SourceCode, token_content: ^Int) | ||||||
| begin | begin | ||||||
|   token_content^ := 0; |   token_content^ := 0; | ||||||
|  |  | ||||||
| @@ -515,7 +516,7 @@ begin | |||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
| proc print_tokens(tokens: ^Token, tokens_size: Word); | proc print_tokens(tokens: ^Token, tokens_size: Word) | ||||||
| var | var | ||||||
|   current_token: ^Token |   current_token: ^Token | ||||||
|   i: Word |   i: Word | ||||||
| @@ -549,8 +550,8 @@ begin | |||||||
| 	    write_s("CONST") | 	    write_s("CONST") | ||||||
| 	  | TokenKind._var: | 	  | TokenKind._var: | ||||||
| 	    write_s("VAR") | 	    write_s("VAR") | ||||||
|    	  | TokenKind.array: |    	  | TokenKind._case: | ||||||
| 	    write_s("ARRAY") | 	    write_s("CASE") | ||||||
| 	  | TokenKind._of: | 	  | TokenKind._of: | ||||||
| 	    write_s("OF") | 	    write_s("OF") | ||||||
| 	  | TokenKind._type: | 	  | TokenKind._type: | ||||||
| @@ -559,8 +560,8 @@ begin | |||||||
| 	    write_s("RECORD") | 	    write_s("RECORD") | ||||||
| 	  | TokenKind._union: | 	  | TokenKind._union: | ||||||
| 	    write_s("UNION") | 	    write_s("UNION") | ||||||
| 	  | TokenKind.pointer: | 	  | TokenKind.pipe: | ||||||
| 	    write_s("POINTER") | 	    write_s("|") | ||||||
| 	  | TokenKind.to: | 	  | TokenKind.to: | ||||||
| 	    write_s("TO") | 	    write_s("TO") | ||||||
| 	  | TokenKind.boolean: | 	  | TokenKind.boolean: | ||||||
| @@ -570,11 +571,11 @@ begin | |||||||
| 	  | TokenKind._nil: | 	  | TokenKind._nil: | ||||||
| 	    write_s("NIL") | 	    write_s("NIL") | ||||||
| 	  | TokenKind.and: | 	  | TokenKind.and: | ||||||
| 	    write_s("AND") | 	    write_s("&") | ||||||
| 	  | TokenKind._or: | 	  | TokenKind._or: | ||||||
| 	    write_s("OR") | 	    write_s("OR") | ||||||
| 	  | TokenKind.not: | 	  | TokenKind.not: | ||||||
| 	    write_s("NOT") | 	    write_s("~") | ||||||
| 	  | TokenKind._return: | 	  | TokenKind._return: | ||||||
| 	    write_s("RETURN") | 	    write_s("RETURN") | ||||||
| 	  | TokenKind._cast: | 	  | TokenKind._cast: | ||||||
| @@ -587,6 +588,9 @@ begin | |||||||
| 	    write_c('<'); | 	    write_c('<'); | ||||||
|         write_s(current_token^.value.string); |         write_s(current_token^.value.string); | ||||||
| 	    write_c('>') | 	    write_c('>') | ||||||
|  | 	  | TokenKind.trait: | ||||||
|  | 	    write_c('#'); | ||||||
|  | 		write_s(current_token^.value.string) | ||||||
| 	  | TokenKind.left_paren: | 	  | TokenKind.left_paren: | ||||||
| 	    write_s("(") | 	    write_s("(") | ||||||
| 	  | TokenKind.right_paren: | 	  | TokenKind.right_paren: | ||||||
| @@ -665,7 +669,7 @@ begin | |||||||
|   write_c('\n') |   write_c('\n') | ||||||
| end | end | ||||||
|  |  | ||||||
| proc categorize_identifier(token_content: String) -> Token; | proc categorize_identifier(token_content: String) -> Token | ||||||
| var | var | ||||||
|   current_token: Token |   current_token: Token | ||||||
| begin | begin | ||||||
| @@ -693,8 +697,8 @@ begin | |||||||
| 	current_token.kind := TokenKind._const | 	current_token.kind := TokenKind._const | ||||||
|   elsif "var" = token_content then |   elsif "var" = token_content then | ||||||
| 	current_token.kind := TokenKind._var | 	current_token.kind := TokenKind._var | ||||||
|   elsif "array" = token_content then |   elsif "case" = token_content then | ||||||
| 	current_token.kind := TokenKind.array | 	current_token.kind := TokenKind._case | ||||||
|   elsif "of" = token_content then |   elsif "of" = token_content then | ||||||
| 	current_token.kind := TokenKind._of | 	current_token.kind := TokenKind._of | ||||||
|   elsif "type" = token_content then |   elsif "type" = token_content then | ||||||
| @@ -703,8 +707,6 @@ begin | |||||||
| 	current_token.kind := TokenKind._record | 	current_token.kind := TokenKind._record | ||||||
|   elsif "union" = token_content then |   elsif "union" = token_content then | ||||||
| 	current_token.kind := TokenKind._union | 	current_token.kind := TokenKind._union | ||||||
|   elsif "pointer" = token_content then |  | ||||||
| 	current_token.kind := TokenKind.pointer |  | ||||||
|   elsif "to" = token_content then |   elsif "to" = token_content then | ||||||
| 	current_token.kind := TokenKind.to | 	current_token.kind := TokenKind.to | ||||||
|   elsif "true" = token_content then |   elsif "true" = token_content then | ||||||
| @@ -715,12 +717,8 @@ begin | |||||||
| 	current_token.value.boolean_value := false | 	current_token.value.boolean_value := false | ||||||
|   elsif "nil" = token_content then |   elsif "nil" = token_content then | ||||||
| 	current_token.kind := TokenKind._nil | 	current_token.kind := TokenKind._nil | ||||||
|   elsif "and" = token_content then |  | ||||||
| 	current_token.kind := TokenKind.and |  | ||||||
|   elsif "or" = token_content then |   elsif "or" = token_content then | ||||||
| 	current_token.kind := TokenKind._or | 	current_token.kind := TokenKind._or | ||||||
|   elsif "not" = token_content then |  | ||||||
| 	current_token.kind := TokenKind.not |  | ||||||
|   elsif "return" = token_content then |   elsif "return" = token_content then | ||||||
| 	current_token.kind := TokenKind._return | 	current_token.kind := TokenKind._return | ||||||
|   elsif "cast" = token_content then |   elsif "cast" = token_content then | ||||||
| @@ -735,7 +733,7 @@ begin | |||||||
|   return current_token |   return current_token | ||||||
| end | end | ||||||
|  |  | ||||||
| proc tokenize(source_code: SourceCode, tokens_size: ^Word) -> ^Token; | proc tokenize(source_code: SourceCode, tokens_size: ^Word) -> ^Token | ||||||
| var | var | ||||||
|   tokens, current_token: ^Token |   tokens, current_token: ^Token | ||||||
|   first_char: Char |   first_char: Char | ||||||
| @@ -755,6 +753,12 @@ begin | |||||||
|     if is_alpha(first_char) or first_char = '_' then |     if is_alpha(first_char) or first_char = '_' then | ||||||
|       lex_identifier(@source_code, @token_buffer); |       lex_identifier(@source_code, @token_buffer); | ||||||
|       current_token^ := categorize_identifier(string_buffer_clear(@token_buffer)) |       current_token^ := categorize_identifier(string_buffer_clear(@token_buffer)) | ||||||
|  | 	elsif first_char = '#' then | ||||||
|  | 	  source_code_advance(@source_code); | ||||||
|  | 	  lex_identifier(@source_code, @token_buffer); | ||||||
|  |  | ||||||
|  | 	  current_token^.kind := TokenKind.trait; | ||||||
|  | 	  current_token^.value.string := string_dup(string_buffer_clear(@token_buffer)) | ||||||
| 	elsif is_digit(first_char) then | 	elsif is_digit(first_char) then | ||||||
| 	  lex_number(@source_code, @current_token^.value.int_value); | 	  lex_number(@source_code, @current_token^.value.int_value); | ||||||
|  |  | ||||||
| @@ -894,6 +898,15 @@ begin | |||||||
| 	elsif first_char = '!' then | 	elsif first_char = '!' then | ||||||
| 	  current_token^.kind := TokenKind.exclamation; | 	  current_token^.kind := TokenKind.exclamation; | ||||||
| 	  source_code_advance(@source_code) | 	  source_code_advance(@source_code) | ||||||
|  | 	elsif first_char = '&' then | ||||||
|  | 	  current_token^.kind := TokenKind.and; | ||||||
|  | 	  source_code_advance(@source_code) | ||||||
|  | 	elsif first_char = '~' then | ||||||
|  | 	  current_token^.kind := TokenKind.not; | ||||||
|  | 	  source_code_advance(@source_code) | ||||||
|  | 	elsif first_char = '|' then | ||||||
|  | 	  current_token^.kind := TokenKind.pipe; | ||||||
|  | 	  source_code_advance(@source_code) | ||||||
| 	else | 	else | ||||||
| 	  current_token^.kind := TokenKind.unknown; | 	  current_token^.kind := TokenKind.unknown; | ||||||
| 	  source_code_advance(@source_code) | 	  source_code_advance(@source_code) | ||||||
| @@ -912,7 +925,7 @@ begin | |||||||
|   return tokens |   return tokens | ||||||
| end | end | ||||||
|  |  | ||||||
| proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine; | proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine | ||||||
| var | var | ||||||
|   parameter: ^^Char |   parameter: ^^Char | ||||||
|   i: Int |   i: Int | ||||||
| @@ -953,7 +966,7 @@ begin | |||||||
|   return result |   return result | ||||||
| end | end | ||||||
|  |  | ||||||
| proc process(argc: Int, argv: ^^Char) -> Int; | proc process(argc: Int, argv: ^^Char) -> Int | ||||||
| var | var | ||||||
|   tokens: ^Token |   tokens: ^Token | ||||||
|   tokens_size: Word |   tokens_size: Word | ||||||
|   | |||||||
							
								
								
									
										204
									
								
								tools/init.c
									
									
									
									
									
								
							
							
						
						
									
										204
									
								
								tools/init.c
									
									
									
									
									
								
							| @@ -1,204 +0,0 @@ | |||||||
| #include <stdio.h> |  | ||||||
| #include <dirent.h> |  | ||||||
| #include <fcntl.h> |  | ||||||
| #include <unistd.h> |  | ||||||
| #include <sys/stat.h> |  | ||||||
| #include <sys/wait.h> |  | ||||||
| #include <sys/reboot.h> |  | ||||||
|  |  | ||||||
| #define FILENAME_BUFFER_SIZE 256 |  | ||||||
|  |  | ||||||
| size_t read_command(int descriptor, char *command_buffer) |  | ||||||
| { |  | ||||||
|     ssize_t bytes_read = 0; |  | ||||||
|     size_t read_so_far = 0; |  | ||||||
|  |  | ||||||
|     while ((bytes_read = read(descriptor, command_buffer + read_so_far, FILENAME_BUFFER_SIZE - read_so_far - 1)) > 0) |  | ||||||
|     { |  | ||||||
|         read_so_far += bytes_read; |  | ||||||
|         if (read_so_far >= FILENAME_BUFFER_SIZE - 1) |  | ||||||
|         { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     command_buffer[read_so_far] = 0; |  | ||||||
|     return read_so_far; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| enum status |  | ||||||
| { |  | ||||||
|     status_success, |  | ||||||
|     status_failure, |  | ||||||
|     status_warning, |  | ||||||
|     status_fatal |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| unsigned int make_path(char *destination, const char *directory, const char *filename, const char *extension) |  | ||||||
| { |  | ||||||
|     unsigned int i = 0; |  | ||||||
|  |  | ||||||
|     for (; i < FILENAME_BUFFER_SIZE; i++) |  | ||||||
|     { |  | ||||||
|         if (directory[i] == 0) |  | ||||||
|         { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         destination[i] = directory[i]; |  | ||||||
|     } |  | ||||||
|     for (int j = 0; i < FILENAME_BUFFER_SIZE; i++, j++) |  | ||||||
|     { |  | ||||||
|         if (filename[j] == 0) |  | ||||||
|         { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         destination[i] = filename[j]; |  | ||||||
|     } |  | ||||||
|     if (extension == NULL) |  | ||||||
|     { |  | ||||||
|         goto done; |  | ||||||
|     } |  | ||||||
|     for (int j = 0; i < FILENAME_BUFFER_SIZE; i++, j++) |  | ||||||
|     { |  | ||||||
|         if (extension[j] == 0) |  | ||||||
|         { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         destination[i] = extension[j]; |  | ||||||
|     } |  | ||||||
| done: |  | ||||||
|     destination[i] = 0; |  | ||||||
|  |  | ||||||
|     return i; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| enum status run_test(const char *file_entry_name) |  | ||||||
| { |  | ||||||
|     printf("Running %s. ", file_entry_name); |  | ||||||
|  |  | ||||||
|     char filename[FILENAME_BUFFER_SIZE]; |  | ||||||
|     char command_buffer[FILENAME_BUFFER_SIZE]; |  | ||||||
|     char file_buffer[256]; |  | ||||||
|     int pipe_ends[2]; |  | ||||||
|  |  | ||||||
|     if (pipe(pipe_ends) == -1) |  | ||||||
|     { |  | ||||||
|         perror("pipe"); |  | ||||||
|         return status_fatal; |  | ||||||
|     } |  | ||||||
|     make_path(filename, "./tests/", file_entry_name, NULL); |  | ||||||
|  |  | ||||||
|     int child_pid = fork(); |  | ||||||
|     if (child_pid == -1) |  | ||||||
|     { |  | ||||||
|         return status_fatal; |  | ||||||
|     } |  | ||||||
|     else if (child_pid == 0) |  | ||||||
|     { |  | ||||||
|         close(STDIN_FILENO); |  | ||||||
|         close(STDERR_FILENO); |  | ||||||
|         close(pipe_ends[0]); // Close the read end. |  | ||||||
|  |  | ||||||
|         if (dup2(pipe_ends[1], STDOUT_FILENO) == -1) |  | ||||||
|         { |  | ||||||
|             perror("dup2"); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             execl(filename, filename); |  | ||||||
|             perror("execl"); |  | ||||||
|         } |  | ||||||
|         close(STDOUT_FILENO); |  | ||||||
|         close(pipe_ends[1]); |  | ||||||
|         _exit(1); |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
|         close(pipe_ends[1]); // Close the write end. |  | ||||||
|         read_command(pipe_ends[0], command_buffer); |  | ||||||
|         close(pipe_ends[0]); |  | ||||||
|  |  | ||||||
|         int wait_status = 0; |  | ||||||
|  |  | ||||||
|         make_path(filename, "./expectations/", file_entry_name, ".txt"); |  | ||||||
|  |  | ||||||
|         FILE *expectation_descriptor = fopen(filename, "r"); |  | ||||||
|  |  | ||||||
|         if (expectation_descriptor == NULL) |  | ||||||
|         { |  | ||||||
|             return status_warning; |  | ||||||
|         } |  | ||||||
|         size_t read_from_file = fread(file_buffer, 1, sizeof(file_buffer) - 1, expectation_descriptor); |  | ||||||
|         fclose(expectation_descriptor); |  | ||||||
|  |  | ||||||
|         file_buffer[read_from_file] = 0; |  | ||||||
|         for (unsigned int i = 0; ; ++i) |  | ||||||
|         { |  | ||||||
|             if (command_buffer[i] == 0 && file_buffer[i] == 0) |  | ||||||
|             { |  | ||||||
|                 fwrite("\n", 1, 1, stdout); |  | ||||||
|                 return status_success; |  | ||||||
|             } |  | ||||||
|             else if (command_buffer[i] != file_buffer[i]) |  | ||||||
|             { |  | ||||||
|                 printf("Failed. Got:\n%s", command_buffer); |  | ||||||
|                 return status_failure; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| struct summary |  | ||||||
| { |  | ||||||
|     size_t total; |  | ||||||
|     size_t failure; |  | ||||||
|     size_t success; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| void walk() |  | ||||||
| { |  | ||||||
|     DIR *directory_stream = opendir("./tests"); |  | ||||||
|     struct dirent *file_entry; |  | ||||||
|  |  | ||||||
|     struct summary test_summary = { .total = 0, .failure = 0, .success = 0 }; |  | ||||||
|  |  | ||||||
|     while ((file_entry = readdir(directory_stream)) != NULL) |  | ||||||
|     { |  | ||||||
|         if (file_entry->d_name[0] == '.') |  | ||||||
|         { |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
|         ++test_summary.total; |  | ||||||
|         switch (run_test(file_entry->d_name)) |  | ||||||
|         { |  | ||||||
|             case status_failure: |  | ||||||
|                 ++test_summary.failure; |  | ||||||
|                 break; |  | ||||||
|             case status_success: |  | ||||||
|                 ++test_summary.success; |  | ||||||
|                 break; |  | ||||||
|             case status_warning: |  | ||||||
|                 break; |  | ||||||
|             case status_fatal: |  | ||||||
|                 goto end_walk; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     printf("Successful: %lu, Failed: %lu, Total: %lu.\n", |  | ||||||
|             test_summary.success, test_summary.failure, test_summary.total); |  | ||||||
| end_walk: |  | ||||||
|     closedir(directory_stream); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int main() |  | ||||||
| { |  | ||||||
|     int dev_console = open("/dev/console", O_WRONLY); |  | ||||||
|     if (dev_console != -1) |  | ||||||
|     { |  | ||||||
|         dup2(dev_console, STDOUT_FILENO); |  | ||||||
|         walk(); |  | ||||||
|         close(dev_console); |  | ||||||
|     } |  | ||||||
|     sync(); |  | ||||||
|     reboot(RB_POWER_OFF); |  | ||||||
|  |  | ||||||
|     return 1; |  | ||||||
| } |  | ||||||
		Reference in New Issue
	
	Block a user