Fix diagnostic for primitive types
This commit is contained in:
parent
4bf88a92e8
commit
33aca4cc07
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1 @@
|
|||||||
/build/
|
/build/
|
||||||
.cache/
|
|
||||||
CMakeFiles/
|
|
||||||
CMakeCache.txt
|
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.21)
|
|
||||||
project(Elna)
|
|
||||||
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
|
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
|
||||||
|
|
||||||
find_package(Boost CONFIG COMPONENTS process program_options REQUIRED)
|
|
||||||
find_package(FLEX REQUIRED)
|
|
||||||
find_package(BISON REQUIRED)
|
|
||||||
|
|
||||||
FLEX_TARGET(lexer boot/lexer.ll ${CMAKE_CURRENT_BINARY_DIR}/lexer.cc)
|
|
||||||
BISON_TARGET(parser boot/parser.yy ${CMAKE_CURRENT_BINARY_DIR}/parser.cc)
|
|
||||||
add_flex_bison_dependency(lexer parser)
|
|
||||||
|
|
||||||
add_library(elna-frontend
|
|
||||||
boot/ast.cc include/elna/boot/ast.h
|
|
||||||
include/elna/boot/symbol.h
|
|
||||||
boot/driver.cc include/elna/boot/driver.h
|
|
||||||
boot/result.cc include/elna/boot/result.h
|
|
||||||
${BISON_parser_OUTPUTS} ${FLEX_lexer_OUTPUTS}
|
|
||||||
)
|
|
||||||
target_include_directories(elna-frontend PRIVATE ${CMAKE_CURRENT_BINARY_DIR} include)
|
|
||||||
target_compile_options(elna-frontend PRIVATE
|
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions -fno-rtti>
|
|
||||||
)
|
|
||||||
|
|
||||||
add_executable(elna tools/main.cc)
|
|
||||||
target_link_libraries(elna PRIVATE elna-frontend)
|
|
||||||
target_include_directories(elna PRIVATE ${CMAKE_CURRENT_BINARY_DIR} include ${Boost_INCLUDE_DIR})
|
|
||||||
target_link_libraries(elna LINK_PUBLIC ${Boost_LIBRARIES})
|
|
||||||
target_compile_options(elna PRIVATE
|
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions -fno-rtti>
|
|
||||||
)
|
|
198
Rakefile
198
Rakefile
@ -1,39 +1,179 @@
|
|||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||||
|
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||||
|
# obtain one at https://mozilla.org/MPL/2.0/. -}
|
||||||
|
|
||||||
require 'pathname'
|
require 'pathname'
|
||||||
|
require 'open3'
|
||||||
require 'rake/clean'
|
require 'rake/clean'
|
||||||
require_relative 'rakelib/shared'
|
require_relative 'tools/support'
|
||||||
|
|
||||||
|
# Dependencies.
|
||||||
|
GCC_VERSION = "14.2.0"
|
||||||
|
GCC_PATCH = 'https://raw.githubusercontent.com/Homebrew/formula-patches/f30c309442a60cfb926e780eae5d70571f8ab2cb/gcc/gcc-14.2.0-r2.diff'
|
||||||
|
|
||||||
|
# Paths.
|
||||||
|
HOST_GCC = TMP + 'host/gcc'
|
||||||
|
HOST_INSTALL = TMP + 'host/install'
|
||||||
|
|
||||||
CLOBBER.include TMP
|
CLOBBER.include TMP
|
||||||
|
|
||||||
task :default do
|
directory(TMP + 'tools')
|
||||||
sh 'make -C build'
|
directory HOST_GCC
|
||||||
sh './build/bin/elna'
|
directory HOST_INSTALL
|
||||||
|
|
||||||
|
task default: [TMP + 'elna'] do
|
||||||
|
sh (TMP + 'elna').to_path, '--tokenize', 'source.elna'
|
||||||
end
|
end
|
||||||
|
|
||||||
desc 'Build the bootstrap compiler'
|
namespace :boot do
|
||||||
task :boot do
|
desc 'Download and configure the bootstrap compiler'
|
||||||
# MacOS:
|
task configure: [TMP + 'tools', HOST_GCC, HOST_INSTALL] do
|
||||||
# ---
|
url = URI.parse "https://gcc.gnu.org/pub/gcc/releases/gcc-#{GCC_VERSION}/gcc-#{GCC_VERSION}.tar.xz"
|
||||||
# CC=gcc-14 CXX=g++-14 \
|
options = find_build_target GCC_VERSION
|
||||||
# CFLAGS="-I/opt/homebrew/Cellar/flex/2.6.4_2/include" \
|
source_directory = TMP + "tools/gcc-#{GCC_VERSION}"
|
||||||
# CXXFLAGS="-I/opt/homebrew/Cellar/flex/2.6.4_2/include" \
|
frontend_link = source_directory + 'gcc'
|
||||||
# ../gcc-14.2.0/configure \
|
|
||||||
# --disable-bootstrap \
|
download_and_pipe url, source_directory.dirname, ['tar', '-Jxv']
|
||||||
# --enable-languages=c,c++,elna \
|
download_and_pipe URI.parse(GCC_PATCH), source_directory, ['patch', '-p1']
|
||||||
# --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX15.2.sdk \
|
|
||||||
# --prefix=$(realpath ../gcc-install)
|
sh 'contrib/download_prerequisites', chdir: source_directory.to_path
|
||||||
|
File.symlink Pathname.new('.').relative_path_from(frontend_link), (frontend_link + 'elna')
|
||||||
|
|
||||||
|
configure_options = [
|
||||||
|
"--prefix=#{HOST_INSTALL.realpath}",
|
||||||
|
"--with-sysroot=#{options.sysroot.realpath}",
|
||||||
|
'--enable-languages=c,c++,elna',
|
||||||
|
'--disable-bootstrap',
|
||||||
|
'--disable-multilib',
|
||||||
|
"--target=#{options.build}",
|
||||||
|
"--build=#{options.build}",
|
||||||
|
"--host=#{options.build}"
|
||||||
|
]
|
||||||
|
flags = '-O2 -fPIC -I/opt/homebrew/Cellar/flex/2.6.4_2/include'
|
||||||
|
env = {
|
||||||
|
'CC' => options.gcc,
|
||||||
|
'CXX' => options.gxx,
|
||||||
|
'CFLAGS' => flags,
|
||||||
|
'CXXFLAGS' => flags,
|
||||||
|
}
|
||||||
|
configure = source_directory.relative_path_from(HOST_GCC) + 'configure'
|
||||||
|
sh env, configure.to_path, *configure_options, chdir: HOST_GCC.to_path
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'Make and install the bootstrap compiler'
|
||||||
|
task :make do
|
||||||
|
cwd = HOST_GCC.to_path
|
||||||
|
|
||||||
|
sh 'make', '-j', Etc.nprocessors.to_s, chdir: cwd
|
||||||
|
sh 'make', 'install', chdir: cwd
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc 'Build cross toolchain'
|
file (TMP + 'elna').to_path => ['source.elna']
|
||||||
task :cross, [:target] do |_, args|
|
file (TMP + 'elna').to_path => [(HOST_INSTALL + 'bin/gelna').to_path] do |task|
|
||||||
args.with_defaults target: 'riscv32-unknown-linux-gnu'
|
sh (HOST_INSTALL + 'bin/gelna').to_path, '-o', task.name, task.prerequisites.first
|
||||||
options = find_build_target GCC_VERSION, args[:target]
|
end
|
||||||
|
|
||||||
options.tools.mkpath
|
namespace :cross do
|
||||||
binutils options
|
desc 'Build cross toolchain'
|
||||||
gcc1 options
|
task :init, [:target] do |_, args|
|
||||||
headers options
|
args.with_defaults target: 'riscv32-unknown-linux-gnu'
|
||||||
kernel options
|
|
||||||
glibc options
|
options = find_build_target GCC_VERSION, args[:target]
|
||||||
gcc2 options
|
env = {
|
||||||
Rake::Task['cross:init'].invoke args[:target]
|
'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}"
|
||||||
|
}
|
||||||
|
sh env, 'riscv32-unknown-linux-gnu-gcc',
|
||||||
|
'-ffreestanding', '-static',
|
||||||
|
'-o', (options.tools + 'init').to_path,
|
||||||
|
'tools/init.c'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
namespace :test do
|
||||||
|
test_sources = FileList['tests/vm/*.elna', 'tests/vm/*.s']
|
||||||
|
compiler = TMP + 'bin/elna'
|
||||||
|
object_directory = TMP + 'riscv/tests'
|
||||||
|
root_directory = TMP + 'riscv/root'
|
||||||
|
executable_directory = root_directory + 'tests'
|
||||||
|
expectation_directory = root_directory + 'expectations'
|
||||||
|
init = TMP + 'riscv/root/init'
|
||||||
|
builtin = TMP + 'riscv/builtin.o'
|
||||||
|
|
||||||
|
directory root_directory
|
||||||
|
directory object_directory
|
||||||
|
directory executable_directory
|
||||||
|
directory expectation_directory
|
||||||
|
|
||||||
|
file builtin => ['tools/builtin.s', object_directory] do |task|
|
||||||
|
sh AS, '-o', task.name, task.prerequisites.first
|
||||||
|
end
|
||||||
|
|
||||||
|
test_files = test_sources.flat_map do |test_source|
|
||||||
|
test_basename = File.basename(test_source, '.*')
|
||||||
|
test_object = object_directory + test_basename.ext('.o')
|
||||||
|
|
||||||
|
file test_object => [test_source, object_directory] do |task|
|
||||||
|
case File.extname(task.prerequisites.first)
|
||||||
|
when '.s'
|
||||||
|
sh AS, '-mno-relax', '-o', task.name, task.prerequisites.first
|
||||||
|
when '.elna'
|
||||||
|
sh compiler, '--output', task.name, task.prerequisites.first
|
||||||
|
else
|
||||||
|
raise "Unknown source file extension #{task.prerequisites.first}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
test_executable = executable_directory + test_basename
|
||||||
|
|
||||||
|
file test_executable => [test_object, executable_directory, builtin] do |task|
|
||||||
|
objects = task.prerequisites.filter { |prerequisite| File.file? prerequisite }
|
||||||
|
|
||||||
|
sh LINKER, '-o', test_executable.to_path, *objects
|
||||||
|
end
|
||||||
|
expectation_name = test_basename.ext '.txt'
|
||||||
|
source_expectation = "tests/expectations/#{expectation_name}"
|
||||||
|
target_expectation = expectation_directory + expectation_name
|
||||||
|
|
||||||
|
file target_expectation => [source_expectation, expectation_directory] do
|
||||||
|
cp source_expectation, target_expectation
|
||||||
|
end
|
||||||
|
|
||||||
|
[test_executable, target_expectation]
|
||||||
|
end
|
||||||
|
|
||||||
|
file init => [root_directory] do |task|
|
||||||
|
cp (TMP + 'tools/init'), task.name
|
||||||
|
end
|
||||||
|
# Directories should come first.
|
||||||
|
test_files.unshift executable_directory, expectation_directory, init
|
||||||
|
|
||||||
|
file (TMP + 'riscv/root.cpio') => test_files do |task|
|
||||||
|
root_files = task.prerequisites
|
||||||
|
.map { |prerequisite| Pathname.new(prerequisite).relative_path_from(root_directory).to_path }
|
||||||
|
|
||||||
|
File.open task.name, 'wb' do |cpio_file|
|
||||||
|
cpio_options = {
|
||||||
|
chdir: root_directory.to_path
|
||||||
|
}
|
||||||
|
cpio_stream = Open3.popen2 'cpio', '-o', '--format=newc', cpio_options do |stdin, stdout, wait_thread|
|
||||||
|
stdin.write root_files.join("\n")
|
||||||
|
stdin.close
|
||||||
|
stdout.each { |chunk| cpio_file.write chunk }
|
||||||
|
wait_thread.value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
task :vm => (TMP + 'riscv/root.cpio') do |task|
|
||||||
|
kernels = FileList.glob(TMP + 'tools/linux-*/arch/riscv/boot/Image')
|
||||||
|
|
||||||
|
sh 'qemu-system-riscv32',
|
||||||
|
'-nographic',
|
||||||
|
'-M', 'virt',
|
||||||
|
'-bios', 'default',
|
||||||
|
'-kernel', kernels.first,
|
||||||
|
'-append', 'quiet panic=1',
|
||||||
|
'-initrd', task.prerequisites.first,
|
||||||
|
'-no-reboot'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -42,6 +42,7 @@ elna_OBJS = \
|
|||||||
elna/elna-convert.o \
|
elna/elna-convert.o \
|
||||||
elna/elna-diagnostic.o \
|
elna/elna-diagnostic.o \
|
||||||
elna/elna-tree.o \
|
elna/elna-tree.o \
|
||||||
|
elna/elna-builtins.o \
|
||||||
elna/ast.o \
|
elna/ast.o \
|
||||||
elna/driver.o \
|
elna/driver.o \
|
||||||
elna/lexer.o \
|
elna/lexer.o \
|
||||||
|
@ -29,7 +29,7 @@ compilers="elna1\$(exeext)"
|
|||||||
|
|
||||||
target_libs=""
|
target_libs=""
|
||||||
|
|
||||||
gtfiles="\$(srcdir)/elna/gcc/elna1.cc"
|
gtfiles="\$(srcdir)/elna/gcc/elna1.cc \$(srcdir)/elna/include/elna/gcc/elna1.h"
|
||||||
|
|
||||||
lang_requires_boot_languages=c++
|
lang_requires_boot_languages=c++
|
||||||
|
|
||||||
|
31
gcc/elna-builtins.cc
Normal file
31
gcc/elna-builtins.cc
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include "elna/gcc/elna-builtins.h"
|
||||||
|
#include "elna/gcc/elna1.h"
|
||||||
|
#include "stor-layout.h"
|
||||||
|
#include "stringpool.h"
|
||||||
|
#include "elna/gcc/elna-tree.h"
|
||||||
|
|
||||||
|
namespace elna
|
||||||
|
{
|
||||||
|
namespace gcc
|
||||||
|
{
|
||||||
|
void init_ttree()
|
||||||
|
{
|
||||||
|
elna_int_type_node = long_integer_type_node;
|
||||||
|
elna_word_type_node = size_type_node;
|
||||||
|
elna_char_type_node = unsigned_char_type_node;
|
||||||
|
elna_bool_type_node = boolean_type_node;
|
||||||
|
elna_byte_type_node = make_unsigned_type(8);
|
||||||
|
elna_float_type_node = double_type_node;
|
||||||
|
|
||||||
|
elna_string_type_node = make_node(RECORD_TYPE);
|
||||||
|
tree_chain record_chain;
|
||||||
|
|
||||||
|
record_chain.append(build_field(UNKNOWN_LOCATION, elna_string_type_node, "length", elna_word_type_node));
|
||||||
|
record_chain.append(build_field(UNKNOWN_LOCATION, elna_string_type_node, "ptr",
|
||||||
|
build_pointer_type_for_mode(elna_char_type_node, VOIDmode, true)));
|
||||||
|
|
||||||
|
TYPE_FIELDS(elna_string_type_node) = record_chain.head();
|
||||||
|
layout_type(elna_string_type_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,7 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
|
|
||||||
#include "elna/gcc/elna-diagnostic.h"
|
#include "elna/gcc/elna-diagnostic.h"
|
||||||
#include "elna/gcc/elna-tree.h"
|
#include "elna/gcc/elna-tree.h"
|
||||||
|
#include "elna/gcc/elna1.h"
|
||||||
|
|
||||||
namespace elna
|
namespace elna
|
||||||
{
|
{
|
||||||
@ -33,23 +34,27 @@ namespace gcc
|
|||||||
{
|
{
|
||||||
gcc_assert(TYPE_P(type));
|
gcc_assert(TYPE_P(type));
|
||||||
|
|
||||||
if (type == integer_type_node)
|
if (type == elna_int_type_node)
|
||||||
{
|
{
|
||||||
return "Int";
|
return "Int";
|
||||||
}
|
}
|
||||||
else if (type == unsigned_type_node)
|
else if (type == elna_word_type_node)
|
||||||
{
|
{
|
||||||
return "Word";
|
return "Word";
|
||||||
}
|
}
|
||||||
else if (type == boolean_type_node)
|
else if (type == elna_bool_type_node)
|
||||||
{
|
{
|
||||||
return "Bool";
|
return "Bool";
|
||||||
}
|
}
|
||||||
else if (type == double_type_node)
|
else if (type == elna_byte_type_node)
|
||||||
|
{
|
||||||
|
return "Byte";
|
||||||
|
}
|
||||||
|
else if (type == elna_float_type_node)
|
||||||
{
|
{
|
||||||
return "Float";
|
return "Float";
|
||||||
}
|
}
|
||||||
else if (type == unsigned_char_type_node)
|
else if (type == elna_char_type_node)
|
||||||
{
|
{
|
||||||
return "Char";
|
return "Char";
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,10 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
|
|
||||||
#include "elna/gcc/elna-generic.h"
|
#include "elna/gcc/elna-generic.h"
|
||||||
#include "elna/gcc/elna-diagnostic.h"
|
#include "elna/gcc/elna-diagnostic.h"
|
||||||
|
#include "elna/gcc/elna1.h"
|
||||||
|
|
||||||
#include "input.h"
|
#include "ggc.h"
|
||||||
|
#include "function.h"
|
||||||
#include "cgraph.h"
|
#include "cgraph.h"
|
||||||
#include "gimplify.h"
|
#include "gimplify.h"
|
||||||
#include "stringpool.h"
|
#include "stringpool.h"
|
||||||
@ -42,7 +44,7 @@ namespace gcc
|
|||||||
|
|
||||||
void generic_visitor::visit(boot::call_expression *expression)
|
void generic_visitor::visit(boot::call_expression *expression)
|
||||||
{
|
{
|
||||||
tree symbol = this->symbol_map->lookup(expression->name());
|
tree symbol = this->lookup(expression->name());
|
||||||
|
|
||||||
if (symbol == NULL_TREE)
|
if (symbol == NULL_TREE)
|
||||||
{
|
{
|
||||||
@ -91,13 +93,12 @@ namespace gcc
|
|||||||
{
|
{
|
||||||
auto body_type = build_type(expression->body());
|
auto body_type = build_type(expression->body());
|
||||||
|
|
||||||
this->current_expression = build1(CONVERT_EXPR, this->symbol_map->lookup("Word"), size_in_bytes(body_type));
|
this->current_expression = build1(CONVERT_EXPR, elna_word_type_node, size_in_bytes(body_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool generic_visitor::is_numeric_type(tree type)
|
bool generic_visitor::is_numeric_type(tree type)
|
||||||
{
|
{
|
||||||
return is_integral_type(type)
|
return is_integral_type(type) || type == elna_float_type_node;
|
||||||
|| type == this->symbol_map->lookup("Float");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void generic_visitor::visit(boot::program *program)
|
void generic_visitor::visit(boot::program *program)
|
||||||
@ -124,11 +125,15 @@ namespace gcc
|
|||||||
};
|
};
|
||||||
tree declaration_type = build_function_type_array(integer_type_node, 2, parameter_types.data());
|
tree declaration_type = build_function_type_array(integer_type_node, 2, parameter_types.data());
|
||||||
tree fndecl = build_fn_decl("main", declaration_type);
|
tree fndecl = build_fn_decl("main", declaration_type);
|
||||||
current_function_decl = fndecl;
|
|
||||||
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node);
|
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node);
|
||||||
DECL_CONTEXT(resdecl) = fndecl;
|
DECL_CONTEXT(resdecl) = fndecl;
|
||||||
DECL_RESULT(fndecl) = resdecl;
|
DECL_RESULT(fndecl) = resdecl;
|
||||||
|
|
||||||
|
push_struct_function(fndecl, false);
|
||||||
|
DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc<language_function>();
|
||||||
|
DECL_STRUCT_FUNCTION(fndecl)->language->binding_level = ggc_cleared_alloc<binding_level>();
|
||||||
|
|
||||||
enter_scope();
|
enter_scope();
|
||||||
|
|
||||||
tree_chain argument_chain;
|
tree_chain argument_chain;
|
||||||
@ -139,7 +144,7 @@ namespace gcc
|
|||||||
get_identifier(argument_name.c_str()), parameter_types[i]);
|
get_identifier(argument_name.c_str()), parameter_types[i]);
|
||||||
DECL_CONTEXT(argc_declaration_tree) = fndecl;
|
DECL_CONTEXT(argc_declaration_tree) = fndecl;
|
||||||
DECL_ARG_TYPE(argc_declaration_tree) = parameter_types[i];
|
DECL_ARG_TYPE(argc_declaration_tree) = parameter_types[i];
|
||||||
this->symbol_map->enter(argument_name, argc_declaration_tree);
|
|
||||||
argument_chain.append(argc_declaration_tree);
|
argument_chain.append(argc_declaration_tree);
|
||||||
}
|
}
|
||||||
DECL_ARGUMENTS(fndecl) = argument_chain.head();
|
DECL_ARGUMENTS(fndecl) = argument_chain.head();
|
||||||
@ -161,7 +166,7 @@ namespace gcc
|
|||||||
DECL_EXTERNAL(fndecl) = 0;
|
DECL_EXTERNAL(fndecl) = 0;
|
||||||
DECL_PRESERVE_P(fndecl) = 1;
|
DECL_PRESERVE_P(fndecl) = 1;
|
||||||
|
|
||||||
current_function_decl = NULL_TREE;
|
pop_cfun();
|
||||||
gimplify_function_tree(fndecl);
|
gimplify_function_tree(fndecl);
|
||||||
cgraph_node::finalize_function(fndecl, true);
|
cgraph_node::finalize_function(fndecl, true);
|
||||||
}
|
}
|
||||||
@ -260,18 +265,57 @@ namespace gcc
|
|||||||
return tree_symbol_mapping{ bind_expr, new_block };
|
return tree_symbol_mapping{ bind_expr, new_block };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tree generic_visitor::lookup(const std::string& name)
|
||||||
|
{
|
||||||
|
if (name == "Int")
|
||||||
|
{
|
||||||
|
return elna_int_type_node;
|
||||||
|
}
|
||||||
|
if (name == "Word")
|
||||||
|
{
|
||||||
|
return elna_word_type_node;
|
||||||
|
}
|
||||||
|
if (name == "Char")
|
||||||
|
{
|
||||||
|
return elna_char_type_node;
|
||||||
|
}
|
||||||
|
if (name == "Bool")
|
||||||
|
{
|
||||||
|
return elna_bool_type_node;
|
||||||
|
}
|
||||||
|
if (name == "Byte")
|
||||||
|
{
|
||||||
|
return elna_byte_type_node;
|
||||||
|
}
|
||||||
|
if (name == "Float")
|
||||||
|
{
|
||||||
|
return elna_float_type_node;
|
||||||
|
}
|
||||||
|
if (name == "String")
|
||||||
|
{
|
||||||
|
return elna_string_type_node;
|
||||||
|
}
|
||||||
|
if (current_function_decl != NULL_TREE)
|
||||||
|
{
|
||||||
|
for (tree decl = DECL_ARGUMENTS(current_function_decl); decl; decl = DECL_CHAIN(decl))
|
||||||
|
{
|
||||||
|
if (name == IDENTIFIER_POINTER(DECL_NAME(decl)))
|
||||||
|
{
|
||||||
|
return decl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this->symbol_map->lookup(name);
|
||||||
|
}
|
||||||
|
|
||||||
void generic_visitor::visit(boot::number_literal<std::int32_t> *literal)
|
void generic_visitor::visit(boot::number_literal<std::int32_t> *literal)
|
||||||
{
|
{
|
||||||
auto symbol = this->symbol_map->lookup("Int");
|
this->current_expression = build_int_cst(elna_int_type_node, literal->number());
|
||||||
|
|
||||||
this->current_expression = build_int_cst(symbol, literal->number());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void generic_visitor::visit(boot::number_literal<std::uint32_t> *literal)
|
void generic_visitor::visit(boot::number_literal<std::uint32_t> *literal)
|
||||||
{
|
{
|
||||||
auto symbol = this->symbol_map->lookup("Word");
|
this->current_expression = build_int_cstu(elna_word_type_node, literal->number());
|
||||||
|
|
||||||
this->current_expression = build_int_cstu(symbol, literal->number());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void generic_visitor::visit(boot::number_literal<double> *literal)
|
void generic_visitor::visit(boot::number_literal<double> *literal)
|
||||||
@ -291,16 +335,12 @@ namespace gcc
|
|||||||
|
|
||||||
void generic_visitor::visit(boot::number_literal<bool> *boolean)
|
void generic_visitor::visit(boot::number_literal<bool> *boolean)
|
||||||
{
|
{
|
||||||
auto symbol = this->symbol_map->lookup("Bool");
|
this->current_expression = build_int_cst_type(elna_bool_type_node, boolean->number());
|
||||||
|
|
||||||
this->current_expression = build_int_cst_type(symbol, boolean->number());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void generic_visitor::visit(boot::number_literal<unsigned char> *character)
|
void generic_visitor::visit(boot::number_literal<unsigned char> *character)
|
||||||
{
|
{
|
||||||
auto symbol = this->symbol_map->lookup("Char");
|
this->current_expression = build_int_cstu(elna_char_type_node, character->number());
|
||||||
|
|
||||||
this->current_expression = build_int_cstu(symbol, character->number());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void generic_visitor::visit(boot::number_literal<nullptr_t> *)
|
void generic_visitor::visit(boot::number_literal<nullptr_t> *)
|
||||||
@ -310,11 +350,8 @@ namespace gcc
|
|||||||
|
|
||||||
void generic_visitor::visit(boot::number_literal<std::string> *string)
|
void generic_visitor::visit(boot::number_literal<std::string> *string)
|
||||||
{
|
{
|
||||||
tree index_type = this->symbol_map->lookup("Word");
|
tree index_constant = build_int_cstu(elna_word_type_node, string->number().size());
|
||||||
tree index_constant = build_int_cstu(index_type, string->number().size());
|
tree string_type = build_array_type(elna_char_type_node, build_index_type(index_constant));
|
||||||
tree element_type = this->symbol_map->lookup("Char");
|
|
||||||
tree string_type = build_array_type(element_type, build_index_type(index_constant));
|
|
||||||
tree string_record = this->symbol_map->lookup("String");
|
|
||||||
|
|
||||||
tree string_literal = build_string(string->number().size(), string->number().c_str());
|
tree string_literal = build_string(string->number().size(), string->number().c_str());
|
||||||
TREE_TYPE(string_literal) = string_type;
|
TREE_TYPE(string_literal) = string_type;
|
||||||
@ -322,15 +359,16 @@ namespace gcc
|
|||||||
TREE_READONLY(string_literal) = 1;
|
TREE_READONLY(string_literal) = 1;
|
||||||
TREE_STATIC(string_literal) = 1;
|
TREE_STATIC(string_literal) = 1;
|
||||||
|
|
||||||
string_type = TREE_TYPE(TREE_CHAIN(TYPE_FIELDS(string_record)));
|
string_type = TREE_TYPE(TREE_CHAIN(TYPE_FIELDS(elna_string_type_node)));
|
||||||
string_literal = build4(ARRAY_REF, element_type, string_literal, integer_zero_node, NULL_TREE, NULL_TREE);
|
string_literal = build4(ARRAY_REF, elna_char_type_node,
|
||||||
|
string_literal, integer_zero_node, NULL_TREE, NULL_TREE);
|
||||||
string_literal = build1(ADDR_EXPR, string_type, string_literal);
|
string_literal = build1(ADDR_EXPR, string_type, string_literal);
|
||||||
|
|
||||||
vec<constructor_elt, va_gc> *elms = NULL;
|
vec<constructor_elt, va_gc> *elms = NULL;
|
||||||
CONSTRUCTOR_APPEND_ELT(elms, TYPE_FIELDS(string_record), index_constant);
|
CONSTRUCTOR_APPEND_ELT(elms, TYPE_FIELDS(elna_string_type_node), index_constant);
|
||||||
CONSTRUCTOR_APPEND_ELT(elms, TREE_CHAIN(TYPE_FIELDS(string_record)), string_literal);
|
CONSTRUCTOR_APPEND_ELT(elms, TREE_CHAIN(TYPE_FIELDS(elna_string_type_node)), string_literal);
|
||||||
|
|
||||||
this->current_expression = build_constructor(string_record, elms);
|
this->current_expression = build_constructor(elna_string_type_node, elms);
|
||||||
}
|
}
|
||||||
|
|
||||||
tree generic_visitor::build_arithmetic_operation(boot::binary_expression *expression,
|
tree generic_visitor::build_arithmetic_operation(boot::binary_expression *expression,
|
||||||
@ -344,23 +382,21 @@ namespace gcc
|
|||||||
tree_code operator_code, tree left, tree right)
|
tree_code operator_code, tree left, tree right)
|
||||||
{
|
{
|
||||||
return build_binary_operation(is_numeric_type(TREE_TYPE(left)) || is_pointer_type(TREE_TYPE(left)),
|
return build_binary_operation(is_numeric_type(TREE_TYPE(left)) || is_pointer_type(TREE_TYPE(left)),
|
||||||
expression, operator_code, left, right, this->symbol_map->lookup("Bool"));
|
expression, operator_code, left, right, elna_bool_type_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
tree generic_visitor::build_logic_operation(boot::binary_expression *expression,
|
tree generic_visitor::build_logic_operation(boot::binary_expression *expression,
|
||||||
tree_code operator_code, tree left, tree right)
|
tree_code operator_code, tree left, tree right)
|
||||||
{
|
{
|
||||||
auto symbol = this->symbol_map->lookup("Bool");
|
return build_binary_operation(TREE_TYPE(left) == elna_bool_type_node,
|
||||||
|
expression, operator_code, left, right, elna_bool_type_node);
|
||||||
return build_binary_operation(TREE_TYPE(left) == symbol,
|
|
||||||
expression, operator_code, left, right, symbol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tree generic_visitor::build_equality_operation(boot::binary_expression *expression,
|
tree generic_visitor::build_equality_operation(boot::binary_expression *expression,
|
||||||
tree_code operator_code, tree left, tree right)
|
tree_code operator_code, tree left, tree right)
|
||||||
{
|
{
|
||||||
return build_binary_operation(true, expression,
|
return build_binary_operation(true, expression,
|
||||||
operator_code, left, right, this->symbol_map->lookup("Bool"));
|
operator_code, left, right, elna_bool_type_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generic_visitor::visit(boot::binary_expression *expression)
|
void generic_visitor::visit(boot::binary_expression *expression)
|
||||||
@ -388,7 +424,7 @@ namespace gcc
|
|||||||
}
|
}
|
||||||
else if (TREE_TYPE(this->current_expression) == ssizetype)
|
else if (TREE_TYPE(this->current_expression) == ssizetype)
|
||||||
{
|
{
|
||||||
this->current_expression = fold_convert(this->symbol_map->lookup("Int"), this->current_expression);
|
this->current_expression = fold_convert(elna_int_type_node, this->current_expression);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -524,7 +560,7 @@ namespace gcc
|
|||||||
{
|
{
|
||||||
if (boot::basic_type_expression *basic_type = type.is_basic())
|
if (boot::basic_type_expression *basic_type = type.is_basic())
|
||||||
{
|
{
|
||||||
tree symbol = this->symbol_map->lookup(basic_type->base_name());
|
tree symbol = this->lookup(basic_type->base_name());
|
||||||
|
|
||||||
if (symbol != NULL_TREE && TYPE_P(symbol))
|
if (symbol != NULL_TREE && TYPE_P(symbol))
|
||||||
{
|
{
|
||||||
@ -654,7 +690,7 @@ namespace gcc
|
|||||||
|
|
||||||
void generic_visitor::visit(boot::variable_expression *expression)
|
void generic_visitor::visit(boot::variable_expression *expression)
|
||||||
{
|
{
|
||||||
auto symbol = this->symbol_map->lookup(expression->name());
|
auto symbol = this->lookup(expression->name());
|
||||||
|
|
||||||
if (symbol == NULL_TREE)
|
if (symbol == NULL_TREE)
|
||||||
{
|
{
|
||||||
|
@ -17,11 +17,11 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
|
|
||||||
#include "elna/gcc/elna-tree.h"
|
#include "elna/gcc/elna-tree.h"
|
||||||
#include "elna/gcc/elna-diagnostic.h"
|
#include "elna/gcc/elna-diagnostic.h"
|
||||||
|
#include "elna/gcc/elna1.h"
|
||||||
|
|
||||||
#include "stor-layout.h"
|
#include "stor-layout.h"
|
||||||
#include "fold-const.h"
|
#include "fold-const.h"
|
||||||
#include "diagnostic-core.h"
|
#include "diagnostic-core.h"
|
||||||
#include "stringpool.h"
|
|
||||||
|
|
||||||
namespace elna
|
namespace elna
|
||||||
{
|
{
|
||||||
@ -144,33 +144,6 @@ namespace gcc
|
|||||||
return field_declaration;
|
return field_declaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<boot::symbol_table<tree>> builtin_symbol_table()
|
|
||||||
{
|
|
||||||
std::shared_ptr<boot::symbol_table<tree>> initial_table =
|
|
||||||
std::make_shared<boot::symbol_table<tree>>();
|
|
||||||
|
|
||||||
initial_table->enter("Int", long_integer_type_node);
|
|
||||||
initial_table->enter("Word", size_type_node);
|
|
||||||
initial_table->enter("Bool", boolean_type_node);
|
|
||||||
initial_table->enter("Float", double_type_node);
|
|
||||||
initial_table->enter("Char", unsigned_char_type_node);
|
|
||||||
initial_table->enter("Byte", make_unsigned_type(8));
|
|
||||||
|
|
||||||
tree string_record = make_node(RECORD_TYPE);
|
|
||||||
tree_chain record_chain;
|
|
||||||
|
|
||||||
record_chain.append(build_field(UNKNOWN_LOCATION, string_record, "length", initial_table->lookup("Word")));
|
|
||||||
record_chain.append(build_field(UNKNOWN_LOCATION, string_record, "ptr",
|
|
||||||
build_pointer_type_for_mode(initial_table->lookup("Char"), VOIDmode, true)));
|
|
||||||
|
|
||||||
TYPE_FIELDS(string_record) = record_chain.head();
|
|
||||||
layout_type(string_record);
|
|
||||||
|
|
||||||
initial_table->enter("String", string_record);
|
|
||||||
|
|
||||||
return initial_table;
|
|
||||||
}
|
|
||||||
|
|
||||||
tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right)
|
tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right)
|
||||||
{
|
{
|
||||||
if (binary_operator == boot::binary_operator::sum)
|
if (binary_operator == boot::binary_operator::sum)
|
||||||
|
57
gcc/elna1.cc
57
gcc/elna1.cc
@ -19,6 +19,9 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "coretypes.h"
|
#include "coretypes.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
|
#include "function.h"
|
||||||
|
#include "tree.h"
|
||||||
|
#include "elna/gcc/elna1.h"
|
||||||
#include "diagnostic.h"
|
#include "diagnostic.h"
|
||||||
#include "opts.h"
|
#include "opts.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@ -26,25 +29,14 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
#include "langhooks-def.h"
|
#include "langhooks-def.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <elna/boot/driver.h>
|
#include "elna/boot/driver.h"
|
||||||
#include "elna/gcc/elna-tree.h"
|
#include "elna/gcc/elna-tree.h"
|
||||||
#include "elna/gcc/elna-generic.h"
|
#include "elna/gcc/elna-generic.h"
|
||||||
#include "elna/gcc/elna-diagnostic.h"
|
#include "elna/gcc/elna-diagnostic.h"
|
||||||
|
#include "elna/gcc/elna-builtins.h"
|
||||||
#include "parser.hh"
|
#include "parser.hh"
|
||||||
|
|
||||||
/* Language-dependent contents of a type. */
|
tree elna_global_trees[ELNA_TI_MAX];
|
||||||
|
|
||||||
struct GTY (()) lang_type
|
|
||||||
{
|
|
||||||
char dummy;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Language-dependent contents of a decl. */
|
|
||||||
|
|
||||||
struct GTY (()) lang_decl
|
|
||||||
{
|
|
||||||
char dummy;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The resulting tree type. */
|
/* The resulting tree type. */
|
||||||
|
|
||||||
@ -56,18 +48,13 @@ union GTY ((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
|
|||||||
union tree_node GTY ((tag ("0"), desc ("tree_node_structure (&%h)"))) generic;
|
union tree_node GTY ((tag ("0"), desc ("tree_node_structure (&%h)"))) generic;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* We don't use language_function. */
|
|
||||||
|
|
||||||
struct GTY (()) language_function
|
|
||||||
{
|
|
||||||
int dummy;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Language hooks. */
|
/* Language hooks. */
|
||||||
|
|
||||||
static bool elna_langhook_init(void)
|
static bool elna_langhook_init(void)
|
||||||
{
|
{
|
||||||
build_common_tree_nodes(false);
|
build_common_tree_nodes(false);
|
||||||
|
elna::gcc::init_ttree();
|
||||||
|
|
||||||
build_common_builtin_nodes();
|
build_common_builtin_nodes();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -98,7 +85,7 @@ static void elna_parse_file(const char *filename)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
elna::gcc::generic_visitor generic_visitor{ elna::gcc::builtin_symbol_table() };
|
elna::gcc::generic_visitor generic_visitor{ std::make_shared<elna::boot::symbol_table<tree>>() };
|
||||||
|
|
||||||
generic_visitor.visit(driver.tree.get());
|
generic_visitor.visit(driver.tree.get());
|
||||||
}
|
}
|
||||||
@ -185,7 +172,26 @@ static bool global_bindings_p(void)
|
|||||||
return current_function_decl == NULL_TREE;
|
return current_function_decl == NULL_TREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static tree pushdecl(tree decl)
|
tree getdecls(void)
|
||||||
|
{
|
||||||
|
if (current_function_decl != NULL_TREE)
|
||||||
|
{
|
||||||
|
return f_binding_level->names;
|
||||||
|
}
|
||||||
|
return NULL_TREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
tree pushdecl(tree decl)
|
||||||
|
{
|
||||||
|
if (current_function_decl != NULL_TREE)
|
||||||
|
{
|
||||||
|
TREE_CHAIN(decl) = f_binding_level->names;
|
||||||
|
f_binding_level->names = decl;
|
||||||
|
}
|
||||||
|
return decl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree elna_langhook_builtin_function(tree decl)
|
||||||
{
|
{
|
||||||
return decl;
|
return decl;
|
||||||
}
|
}
|
||||||
@ -203,10 +209,7 @@ static tree pushdecl(tree decl)
|
|||||||
#define LANG_HOOKS_TYPE_FOR_MODE elna_langhook_type_for_mode
|
#define LANG_HOOKS_TYPE_FOR_MODE elna_langhook_type_for_mode
|
||||||
|
|
||||||
#undef LANG_HOOKS_BUILTIN_FUNCTION
|
#undef LANG_HOOKS_BUILTIN_FUNCTION
|
||||||
#define LANG_HOOKS_BUILTIN_FUNCTION pushdecl
|
#define LANG_HOOKS_BUILTIN_FUNCTION elna_langhook_builtin_function
|
||||||
|
|
||||||
#undef LANG_HOOKS_GETDECLS
|
|
||||||
#define LANG_HOOKS_GETDECLS hook_tree_void_null
|
|
||||||
|
|
||||||
#undef LANG_HOOKS_IDENTIFIER_SIZE
|
#undef LANG_HOOKS_IDENTIFIER_SIZE
|
||||||
#define LANG_HOOKS_IDENTIFIER_SIZE sizeof(struct tree_identifier)
|
#define LANG_HOOKS_IDENTIFIER_SIZE sizeof(struct tree_identifier)
|
||||||
|
13
include/elna/gcc/elna-builtins.h
Normal file
13
include/elna/gcc/elna-builtins.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include "config.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "coretypes.h"
|
||||||
|
#include "tree.h"
|
||||||
|
#include "tree-iterator.h"
|
||||||
|
|
||||||
|
namespace elna
|
||||||
|
{
|
||||||
|
namespace gcc
|
||||||
|
{
|
||||||
|
void init_ttree();
|
||||||
|
}
|
||||||
|
}
|
@ -46,6 +46,8 @@ namespace gcc
|
|||||||
void enter_scope();
|
void enter_scope();
|
||||||
tree_symbol_mapping leave_scope();
|
tree_symbol_mapping leave_scope();
|
||||||
|
|
||||||
|
tree lookup(const std::string& name);
|
||||||
|
|
||||||
void make_if_branch(boot::conditional_statements& branch, tree goto_endif);
|
void make_if_branch(boot::conditional_statements& branch, tree goto_endif);
|
||||||
|
|
||||||
bool is_numeric_type(tree type);
|
bool is_numeric_type(tree type);
|
||||||
|
@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
#include "coretypes.h"
|
#include "coretypes.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "tree-iterator.h"
|
#include "tree-iterator.h"
|
||||||
|
#include "stringpool.h"
|
||||||
|
|
||||||
#include "elna/boot/ast.h"
|
#include "elna/boot/ast.h"
|
||||||
#include "elna/boot/symbol.h"
|
#include "elna/boot/symbol.h"
|
||||||
@ -96,8 +97,6 @@ namespace gcc
|
|||||||
tree chain_defer();
|
tree chain_defer();
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<boot::symbol_table<tree>> builtin_symbol_table();
|
|
||||||
|
|
||||||
tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right);
|
tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right);
|
||||||
tree build_binary_operation(bool condition, boot::binary_expression *expression,
|
tree build_binary_operation(bool condition, boot::binary_expression *expression,
|
||||||
tree_code operator_code, tree left, tree right, tree target_type);
|
tree_code operator_code, tree left, tree right, tree target_type);
|
||||||
|
47
include/elna/gcc/elna1.h
Normal file
47
include/elna/gcc/elna1.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
enum elna_tree_index
|
||||||
|
{
|
||||||
|
ELNA_TI_INT_TYPE,
|
||||||
|
ELNA_TI_WORD_TYPE,
|
||||||
|
ELNA_TI_CHAR_TYPE,
|
||||||
|
ELNA_TI_BOOL_TYPE,
|
||||||
|
ELNA_TI_BYTE_TYPE,
|
||||||
|
ELNA_TI_FLOAT_TYPE,
|
||||||
|
ELNA_TI_STRING_TYPE,
|
||||||
|
ELNA_TI_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
extern GTY(()) tree elna_global_trees[ELNA_TI_MAX];
|
||||||
|
|
||||||
|
#define elna_int_type_node elna_global_trees[ELNA_TI_INT_TYPE]
|
||||||
|
#define elna_word_type_node elna_global_trees[ELNA_TI_WORD_TYPE]
|
||||||
|
#define elna_char_type_node elna_global_trees[ELNA_TI_CHAR_TYPE]
|
||||||
|
#define elna_bool_type_node elna_global_trees[ELNA_TI_BOOL_TYPE]
|
||||||
|
#define elna_byte_type_node elna_global_trees[ELNA_TI_BYTE_TYPE]
|
||||||
|
#define elna_float_type_node elna_global_trees[ELNA_TI_FLOAT_TYPE]
|
||||||
|
#define elna_string_type_node elna_global_trees[ELNA_TI_STRING_TYPE]
|
||||||
|
|
||||||
|
/* Language-dependent contents of a type. */
|
||||||
|
struct GTY (()) lang_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Language-dependent contents of a decl. */
|
||||||
|
struct GTY (()) lang_decl
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GTY (()) binding_level
|
||||||
|
{
|
||||||
|
// A chain of all declarations in this binding level.
|
||||||
|
tree names;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GTY (()) language_function
|
||||||
|
{
|
||||||
|
struct binding_level *binding_level;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define f_binding_level DECL_STRUCT_FUNCTION(current_function_decl)->language->binding_level
|
||||||
|
|
||||||
|
extern tree pushdecl(tree);
|
||||||
|
extern tree getdecls(void);
|
@ -1,245 +0,0 @@
|
|||||||
# This Source Code Form is subject to the terms of the Mozilla Public License,
|
|
||||||
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
||||||
# obtain one at https://mozilla.org/MPL/2.0/. -}
|
|
||||||
|
|
||||||
require 'uri'
|
|
||||||
require 'net/http'
|
|
||||||
require 'open3'
|
|
||||||
require 'etc'
|
|
||||||
require 'fileutils'
|
|
||||||
require_relative 'shared'
|
|
||||||
|
|
||||||
BINUTILS_VERSION = '2.43.1'
|
|
||||||
GLIBC_VERSION = '2.40'
|
|
||||||
KERNEL_VERSION = '5.15.166'
|
|
||||||
|
|
||||||
def download_and_unarchive(url, target)
|
|
||||||
case File.extname url.path
|
|
||||||
when '.bz2'
|
|
||||||
archive_type = '-j'
|
|
||||||
root_directory = File.basename url.path, '.tar.bz2'
|
|
||||||
when '.xz'
|
|
||||||
archive_type = '-J'
|
|
||||||
root_directory = File.basename url.path, '.tar.xz'
|
|
||||||
else
|
|
||||||
raise "Unsupported archive type #{url.path}."
|
|
||||||
end
|
|
||||||
|
|
||||||
Net::HTTP.start(url.host, url.port, use_ssl: url.scheme == 'https') do |http|
|
|
||||||
request = Net::HTTP::Get.new url.request_uri
|
|
||||||
|
|
||||||
http.request request do |response|
|
|
||||||
case response
|
|
||||||
when Net::HTTPRedirection
|
|
||||||
download_and_unarchive URI.parse(response['location'])
|
|
||||||
when Net::HTTPSuccess
|
|
||||||
Open3.popen2 'tar', '-C', target.to_path, archive_type, '-xv' do |stdin, stdout, wait_thread|
|
|
||||||
Thread.new do
|
|
||||||
stdout.each { |line| puts line }
|
|
||||||
end
|
|
||||||
|
|
||||||
response.read_body do |chunk|
|
|
||||||
stdin.write chunk
|
|
||||||
end
|
|
||||||
stdin.close
|
|
||||||
|
|
||||||
wait_thread.value
|
|
||||||
end
|
|
||||||
else
|
|
||||||
response.error!
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
target + root_directory
|
|
||||||
end
|
|
||||||
|
|
||||||
def configure_make_install(source_directory, configure_options, env, cwd)
|
|
||||||
configure = source_directory.relative_path_from(cwd) + 'configure'
|
|
||||||
system env, configure.to_path, *configure_options, chdir: cwd.to_path, exception: true
|
|
||||||
system 'make', '-j', Etc.nprocessors.to_s, chdir: cwd.to_path, exception: true
|
|
||||||
system env, 'make', 'install', chdir: cwd.to_path, exception: true
|
|
||||||
end
|
|
||||||
|
|
||||||
# Build cross binutils.
|
|
||||||
def binutils(options)
|
|
||||||
source_directory = download_and_unarchive(
|
|
||||||
URI.parse("https://ftp.gnu.org/gnu/binutils/binutils-#{BINUTILS_VERSION}.tar.xz"),
|
|
||||||
options.tools)
|
|
||||||
|
|
||||||
cwd = source_directory.dirname + 'build-binutils'
|
|
||||||
cwd.mkpath
|
|
||||||
options.rootfs.mkpath
|
|
||||||
|
|
||||||
env = {
|
|
||||||
'CC' => options.gcc,
|
|
||||||
'CXX' => options.gxx
|
|
||||||
}
|
|
||||||
configure_options = [
|
|
||||||
"--prefix=#{options.rootfs.realpath}",
|
|
||||||
"--target=#{options.target}",
|
|
||||||
'--disable-nls',
|
|
||||||
'--enable-gprofng=no',
|
|
||||||
'--disable-werror',
|
|
||||||
'--enable-default-hash-style=gnu',
|
|
||||||
'--disable-libquadmath'
|
|
||||||
]
|
|
||||||
configure_make_install source_directory, configure_options, env, cwd
|
|
||||||
end
|
|
||||||
|
|
||||||
# Build stage 1 GCC.
|
|
||||||
def gcc1(options)
|
|
||||||
source_directory = download_and_unarchive(
|
|
||||||
URI.parse("https://gcc.gnu.org/pub/gcc/releases/gcc-#{GCC_VERSION}/gcc-#{GCC_VERSION}.tar.xz"),
|
|
||||||
options.tools)
|
|
||||||
|
|
||||||
cwd = source_directory.dirname + 'build-gcc'
|
|
||||||
cwd.mkpath
|
|
||||||
options.rootfs.mkpath
|
|
||||||
options.sysroot.mkpath
|
|
||||||
|
|
||||||
system 'contrib/download_prerequisites', chdir: source_directory.to_path, exception: true
|
|
||||||
configure_options = options.configuration + [
|
|
||||||
"--prefix=#{options.rootfs.realpath}",
|
|
||||||
"--with-sysroot=#{options.sysroot.realpath}",
|
|
||||||
'--enable-languages=c,c++',
|
|
||||||
'--disable-shared',
|
|
||||||
'--disable-bootstrap',
|
|
||||||
'--disable-multilib',
|
|
||||||
'--disable-libmudflap',
|
|
||||||
'--disable-libssp',
|
|
||||||
'--disable-libquadmath',
|
|
||||||
'--disable-libsanitizer',
|
|
||||||
'--disable-threads',
|
|
||||||
'--disable-libatomic',
|
|
||||||
'--disable-libgomp',
|
|
||||||
'--disable-libvtv',
|
|
||||||
'--disable-libstdcxx',
|
|
||||||
'--disable-nls',
|
|
||||||
'--with-newlib',
|
|
||||||
'--without-headers',
|
|
||||||
"--target=#{options.target}",
|
|
||||||
"--build=#{options.build}",
|
|
||||||
"--host=#{options.build}"
|
|
||||||
]
|
|
||||||
flags = '-O2 -fPIC'
|
|
||||||
env = {
|
|
||||||
'CC' => options.gcc,
|
|
||||||
'CXX' => options.gxx,
|
|
||||||
'CFLAGS' => flags,
|
|
||||||
'CXXFLAGS' => flags,
|
|
||||||
'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}"
|
|
||||||
}
|
|
||||||
configure_make_install source_directory, configure_options, env, cwd
|
|
||||||
end
|
|
||||||
|
|
||||||
# Copy glibc headers.
|
|
||||||
def headers(options)
|
|
||||||
source_directory = download_and_unarchive(
|
|
||||||
URI.parse("https://ftp.gnu.org/gnu/glibc/glibc-#{GLIBC_VERSION}.tar.xz"),
|
|
||||||
options.tools)
|
|
||||||
include_directory = options.tools + 'include'
|
|
||||||
|
|
||||||
include_directory.mkpath
|
|
||||||
FileUtils.cp (source_directory + 'elf/elf.h'), (include_directory + 'elf.h')
|
|
||||||
end
|
|
||||||
|
|
||||||
# Build linux kernel.
|
|
||||||
def kernel(options)
|
|
||||||
cwd = download_and_unarchive(
|
|
||||||
URI.parse("https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-#{KERNEL_VERSION}.tar.xz"),
|
|
||||||
options.tools)
|
|
||||||
|
|
||||||
env = {
|
|
||||||
'CROSS_COMPILE' => "#{options.target}-",
|
|
||||||
'ARCH' => 'riscv',
|
|
||||||
'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}",
|
|
||||||
'HOSTCFLAGS' => "-D_UUID_T -D__GETHOSTUUID_H -I#{options.tools.realpath + 'include'}"
|
|
||||||
}
|
|
||||||
system env, 'make', 'rv32_defconfig', chdir: cwd.to_path, exception: true
|
|
||||||
system env, 'make', '-j', Etc.nprocessors.to_s, chdir: cwd.to_path, exception: true
|
|
||||||
system env, 'make', 'headers', chdir: cwd.to_path, exception: true
|
|
||||||
|
|
||||||
user_directory = options.sysroot + 'usr'
|
|
||||||
|
|
||||||
user_directory.mkpath
|
|
||||||
FileUtils.cp_r (cwd + 'usr/include'), (user_directory + 'include')
|
|
||||||
end
|
|
||||||
|
|
||||||
# Build glibc.
|
|
||||||
def glibc(options)
|
|
||||||
source_directory = options.tools + "glibc-#{GLIBC_VERSION}"
|
|
||||||
configure_options = [
|
|
||||||
'--prefix=/usr',
|
|
||||||
"--host=#{options.target}",
|
|
||||||
"--target=#{options.target}",
|
|
||||||
"--build=#{options.build}",
|
|
||||||
"--enable-kernel=#{KERNEL_VERSION}",
|
|
||||||
"--with-headers=#{options.sysroot.realpath + 'usr/include'}",
|
|
||||||
'--disable-nscd',
|
|
||||||
'--disable-libquadmath',
|
|
||||||
'--disable-libitm',
|
|
||||||
'--disable-werror',
|
|
||||||
'libc_cv_forced_unwind=yes'
|
|
||||||
]
|
|
||||||
bin = options.rootfs.realpath + 'bin'
|
|
||||||
env = {
|
|
||||||
'PATH' => "#{bin}:#{ENV['PATH']}",
|
|
||||||
'MAKE' => 'make' # Otherwise it uses gnumake which can be different and too old.
|
|
||||||
}
|
|
||||||
cwd = source_directory.dirname + 'build-glibc'
|
|
||||||
cwd.mkpath
|
|
||||||
|
|
||||||
configure = source_directory.relative_path_from(cwd) +'./configure'
|
|
||||||
system env, configure.to_path, *configure_options, chdir: cwd.to_path, exception: true
|
|
||||||
system env, 'make', '-j', Etc.nprocessors.to_s, chdir: cwd.to_path, exception: true
|
|
||||||
system env, 'make', "install_root=#{options.sysroot.realpath}", 'install', chdir: cwd.to_path, exception: true
|
|
||||||
end
|
|
||||||
|
|
||||||
# Build stage 2 GCC.
|
|
||||||
def gcc2(options)
|
|
||||||
source_directory = options.tools + "gcc-#{GCC_VERSION}"
|
|
||||||
cwd = options.tools + 'build-gcc'
|
|
||||||
|
|
||||||
FileUtils.rm_rf cwd
|
|
||||||
cwd.mkpath
|
|
||||||
|
|
||||||
configure_options = options.configuration + [
|
|
||||||
"--prefix=#{options.rootfs.realpath}",
|
|
||||||
"--with-sysroot=#{options.sysroot.realpath}",
|
|
||||||
'--enable-languages=c,c++,lto',
|
|
||||||
'--enable-lto',
|
|
||||||
'--enable-shared',
|
|
||||||
'--disable-bootstrap',
|
|
||||||
'--disable-multilib',
|
|
||||||
'--enable-checking=release',
|
|
||||||
'--disable-libssp',
|
|
||||||
'--disable-libquadmath',
|
|
||||||
'--enable-threads=posix',
|
|
||||||
'--with-default-libstdcxx-abi=new',
|
|
||||||
'--disable-nls',
|
|
||||||
"--target=#{options.target}",
|
|
||||||
"--build=#{options.build}",
|
|
||||||
"--host=#{options.build}"
|
|
||||||
|
|
||||||
]
|
|
||||||
flags = '-O2 -fPIC'
|
|
||||||
env = {
|
|
||||||
'CFLAGS' => flags,
|
|
||||||
'CXXFLAGS' => flags,
|
|
||||||
'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}"
|
|
||||||
}
|
|
||||||
configure_make_install source_directory, configure_options, env, cwd
|
|
||||||
end
|
|
||||||
|
|
||||||
namespace :cross do
|
|
||||||
task :init, [:target] do |_, args|
|
|
||||||
options = find_build_target GCC_VERSION, args[:target]
|
|
||||||
env = {
|
|
||||||
'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}"
|
|
||||||
}
|
|
||||||
sh env, 'riscv32-unknown-linux-gnu-gcc',
|
|
||||||
'-ffreestanding', '-static',
|
|
||||||
'-o', (options.tools + 'init').to_path,
|
|
||||||
'tools/init.c'
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,72 +0,0 @@
|
|||||||
# This Source Code Form is subject to the terms of the Mozilla Public License,
|
|
||||||
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
||||||
# obtain one at https://mozilla.org/MPL/2.0/. -}
|
|
||||||
|
|
||||||
GCC_VERSION = "14.2.0"
|
|
||||||
|
|
||||||
TMP = Pathname.new('./build')
|
|
||||||
|
|
||||||
class BuildTarget
|
|
||||||
attr_accessor(:build, :gcc, :target, :tmp)
|
|
||||||
|
|
||||||
def gxx
|
|
||||||
@gcc.gsub 'c', '+'
|
|
||||||
end
|
|
||||||
|
|
||||||
def sysroot
|
|
||||||
tmp + 'sysroot'
|
|
||||||
end
|
|
||||||
|
|
||||||
def rootfs
|
|
||||||
tmp + 'rootfs'
|
|
||||||
end
|
|
||||||
|
|
||||||
def tools
|
|
||||||
tmp + 'tools'
|
|
||||||
end
|
|
||||||
|
|
||||||
def configuration
|
|
||||||
case target
|
|
||||||
when /^riscv[[:digit:]]+-/
|
|
||||||
[
|
|
||||||
'--with-arch=rv32imafdc',
|
|
||||||
'--with-abi=ilp32d',
|
|
||||||
'--with-tune=rocket',
|
|
||||||
'--with-isa-spec=20191213'
|
|
||||||
]
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def gcc_verbose(gcc_binary)
|
|
||||||
read, write = IO.pipe
|
|
||||||
sh({'LANG' => 'C'}, gcc_binary, '--verbose', err: write)
|
|
||||||
write.close
|
|
||||||
output = read.read
|
|
||||||
read.close
|
|
||||||
output
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_build_target(gcc_version, target)
|
|
||||||
gcc_binary = 'gcc'
|
|
||||||
output = gcc_verbose gcc_binary
|
|
||||||
|
|
||||||
if output.start_with? 'Apple clang'
|
|
||||||
gcc_binary = "gcc-#{gcc_version.split('.').first}"
|
|
||||||
output = gcc_verbose gcc_binary
|
|
||||||
end
|
|
||||||
result = output
|
|
||||||
.lines
|
|
||||||
.each_with_object(BuildTarget.new) do |line, accumulator|
|
|
||||||
if line.start_with? 'Target: '
|
|
||||||
accumulator.build = line.split(' ').last.strip
|
|
||||||
elsif line.start_with? 'COLLECT_GCC'
|
|
||||||
accumulator.gcc = line.split('=').last.strip
|
|
||||||
end
|
|
||||||
end
|
|
||||||
result.tmp = TMP
|
|
||||||
result.target = target
|
|
||||||
result
|
|
||||||
end
|
|
@ -1,100 +0,0 @@
|
|||||||
# This Source Code Form is subject to the terms of the Mozilla Public License,
|
|
||||||
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
||||||
# obtain one at https://mozilla.org/MPL/2.0/. -}
|
|
||||||
|
|
||||||
require 'open3'
|
|
||||||
require 'rake/clean'
|
|
||||||
require_relative 'shared'
|
|
||||||
|
|
||||||
CLEAN.include(TMP + 'riscv')
|
|
||||||
|
|
||||||
LINKER = 'build/rootfs/riscv32-unknown-linux-gnu/bin/ld'
|
|
||||||
AS = 'build/rootfs/riscv32-unknown-linux-gnu/bin/as'
|
|
||||||
|
|
||||||
namespace :test do
|
|
||||||
test_sources = FileList['tests/vm/*.elna', 'tests/vm/*.s']
|
|
||||||
compiler = TMP + 'bin/elna'
|
|
||||||
object_directory = TMP + 'riscv/tests'
|
|
||||||
root_directory = TMP + 'riscv/root'
|
|
||||||
executable_directory = root_directory + 'tests'
|
|
||||||
expectation_directory = root_directory + 'expectations'
|
|
||||||
init = TMP + 'riscv/root/init'
|
|
||||||
builtin = TMP + 'riscv/builtin.o'
|
|
||||||
|
|
||||||
directory root_directory
|
|
||||||
directory object_directory
|
|
||||||
directory executable_directory
|
|
||||||
directory expectation_directory
|
|
||||||
|
|
||||||
file builtin => ['tools/builtin.s', object_directory] do |task|
|
|
||||||
sh AS, '-o', task.name, task.prerequisites.first
|
|
||||||
end
|
|
||||||
|
|
||||||
test_files = test_sources.flat_map do |test_source|
|
|
||||||
test_basename = File.basename(test_source, '.*')
|
|
||||||
test_object = object_directory + test_basename.ext('.o')
|
|
||||||
|
|
||||||
file test_object => [test_source, object_directory] do |task|
|
|
||||||
case File.extname(task.prerequisites.first)
|
|
||||||
when '.s'
|
|
||||||
sh AS, '-mno-relax', '-o', task.name, task.prerequisites.first
|
|
||||||
when '.elna'
|
|
||||||
sh compiler, '--output', task.name, task.prerequisites.first
|
|
||||||
else
|
|
||||||
raise "Unknown source file extension #{task.prerequisites.first}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
test_executable = executable_directory + test_basename
|
|
||||||
|
|
||||||
file test_executable => [test_object, executable_directory, builtin] do |task|
|
|
||||||
objects = task.prerequisites.filter { |prerequisite| File.file? prerequisite }
|
|
||||||
|
|
||||||
sh LINKER, '-o', test_executable.to_path, *objects
|
|
||||||
end
|
|
||||||
expectation_name = test_basename.ext '.txt'
|
|
||||||
source_expectation = "tests/expectations/#{expectation_name}"
|
|
||||||
target_expectation = expectation_directory + expectation_name
|
|
||||||
|
|
||||||
file target_expectation => [source_expectation, expectation_directory] do
|
|
||||||
cp source_expectation, target_expectation
|
|
||||||
end
|
|
||||||
|
|
||||||
[test_executable, target_expectation]
|
|
||||||
end
|
|
||||||
|
|
||||||
file init => [root_directory] do |task|
|
|
||||||
cp (TMP + 'tools/init'), task.name
|
|
||||||
end
|
|
||||||
# Directories should come first.
|
|
||||||
test_files.unshift executable_directory, expectation_directory, init
|
|
||||||
|
|
||||||
file (TMP + 'riscv/root.cpio') => test_files do |task|
|
|
||||||
root_files = task.prerequisites
|
|
||||||
.map { |prerequisite| Pathname.new(prerequisite).relative_path_from(root_directory).to_path }
|
|
||||||
|
|
||||||
File.open task.name, 'wb' do |cpio_file|
|
|
||||||
cpio_options = {
|
|
||||||
chdir: root_directory.to_path
|
|
||||||
}
|
|
||||||
cpio_stream = Open3.popen2 'cpio', '-o', '--format=newc', cpio_options do |stdin, stdout, wait_thread|
|
|
||||||
stdin.write root_files.join("\n")
|
|
||||||
stdin.close
|
|
||||||
stdout.each { |chunk| cpio_file.write chunk }
|
|
||||||
wait_thread.value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
task :vm => (TMP + 'riscv/root.cpio') do |task|
|
|
||||||
kernels = FileList.glob(TMP + 'tools/linux-*/arch/riscv/boot/Image')
|
|
||||||
|
|
||||||
sh 'qemu-system-riscv32',
|
|
||||||
'-nographic',
|
|
||||||
'-M', 'virt',
|
|
||||||
'-bios', 'default',
|
|
||||||
'-kernel', kernels.first,
|
|
||||||
'-append', 'quiet panic=1',
|
|
||||||
'-initrd', task.prerequisites.first,
|
|
||||||
'-no-reboot'
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,41 +0,0 @@
|
|||||||
#include <elna/source/driver.h>
|
|
||||||
#include "parser.hh"
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
constexpr std::size_t pointer_size = 4;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
elna::source::driver driver{ "-" };
|
|
||||||
std::istringstream inp(R"(
|
|
||||||
proc f();
|
|
||||||
begin
|
|
||||||
end;
|
|
||||||
|
|
||||||
var x: Int;
|
|
||||||
|
|
||||||
begin
|
|
||||||
x := 4 + 2
|
|
||||||
end.
|
|
||||||
)");
|
|
||||||
|
|
||||||
elna::source::lexer lexer(inp);
|
|
||||||
yy::parser parser(lexer, driver);
|
|
||||||
|
|
||||||
if (auto result = parser())
|
|
||||||
{
|
|
||||||
for (const auto& error : driver.errors())
|
|
||||||
{
|
|
||||||
std::cerr << error->path << ':'
|
|
||||||
<< error->line() << ':' << error->column()
|
|
||||||
<< ": error: " << error->what()
|
|
||||||
<< '.' << std::endl;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
for (auto& definition : driver.tree->definitions())
|
|
||||||
{
|
|
||||||
std::cout << "Definition identifier: " << definition->identifier() << std::endl;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
92
tools/support.rb
Normal file
92
tools/support.rb
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||||
|
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||||
|
# obtain one at https://mozilla.org/MPL/2.0/. -}
|
||||||
|
|
||||||
|
require 'uri'
|
||||||
|
require 'net/http'
|
||||||
|
require 'open3'
|
||||||
|
|
||||||
|
LINKER = 'build/rootfs/riscv32-unknown-linux-gnu/bin/ld'
|
||||||
|
AS = 'build/rootfs/riscv32-unknown-linux-gnu/bin/as'
|
||||||
|
|
||||||
|
TMP = Pathname.new('./build')
|
||||||
|
|
||||||
|
class BuildTarget
|
||||||
|
attr_accessor(:build, :gcc, :sysroot, :tmp)
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@sysroot = '/'
|
||||||
|
end
|
||||||
|
|
||||||
|
def gxx
|
||||||
|
@gcc.gsub 'c', '+'
|
||||||
|
end
|
||||||
|
|
||||||
|
def rootfs
|
||||||
|
tmp + 'rootfs'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def gcc_verbose(gcc_binary)
|
||||||
|
read, write = IO.pipe
|
||||||
|
sh({'LANG' => 'C'}, gcc_binary, '--verbose', err: write)
|
||||||
|
write.close
|
||||||
|
output = read.read
|
||||||
|
read.close
|
||||||
|
output
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_build_target(gcc_version)
|
||||||
|
gcc_binary = 'gcc'
|
||||||
|
output = gcc_verbose gcc_binary
|
||||||
|
|
||||||
|
if output.start_with? 'Apple clang'
|
||||||
|
gcc_binary = "gcc-#{gcc_version.split('.').first}"
|
||||||
|
output = gcc_verbose gcc_binary
|
||||||
|
sdk = Pathname.new '/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk'
|
||||||
|
end
|
||||||
|
result = output
|
||||||
|
.lines
|
||||||
|
.each_with_object(BuildTarget.new) do |line, accumulator|
|
||||||
|
if line.start_with? 'Target: '
|
||||||
|
accumulator.build = line.split(' ').last.strip
|
||||||
|
elsif line.start_with? 'COLLECT_GCC'
|
||||||
|
accumulator.gcc = line.split('=').last.strip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
result.tmp = TMP
|
||||||
|
result.sysroot = sdk
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def download_and_pipe(url, target, command)
|
||||||
|
target.mkpath
|
||||||
|
|
||||||
|
Net::HTTP.start(url.host, url.port, use_ssl: url.scheme == 'https') do |http|
|
||||||
|
request = Net::HTTP::Get.new url.request_uri
|
||||||
|
|
||||||
|
http.request request do |response|
|
||||||
|
case response
|
||||||
|
when Net::HTTPRedirection
|
||||||
|
download_and_pipe URI.parse(response['location']), target, command
|
||||||
|
when Net::HTTPSuccess
|
||||||
|
Dir.chdir target.to_path do
|
||||||
|
Open3.popen2(*command) do |stdin, stdout, wait_thread|
|
||||||
|
Thread.new do
|
||||||
|
stdout.each { |line| puts line }
|
||||||
|
end
|
||||||
|
|
||||||
|
response.read_body do |chunk|
|
||||||
|
stdin.write chunk
|
||||||
|
end
|
||||||
|
stdin.close
|
||||||
|
|
||||||
|
wait_thread.value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
response.error!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user