Update to GCC 15.1
This commit is contained in:
parent
a02e053ed2
commit
9726fcedd9
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;
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user