Compare commits

..

7 Commits

Author SHA1 Message Date
598bdb1410 ld: switch to ifc-generated ipc interface 2026-02-26 19:48:06 +00:00
285a80530d bootstrap: switch to ifc-generated ipc interface 2026-02-26 19:47:58 +00:00
3b50715559 lib: delete hand-written msg interface libraries 2026-02-26 19:47:37 +00:00
bdb2e0ed50 interface: add sample filesystem interface 2026-02-26 19:47:16 +00:00
01109948b2 meta: add tool to combine multiple compile-commands database files
this allows once instance of an lsp to understand multiple
cmake build directories.
2026-02-26 19:46:13 +00:00
dc93f7db4c cmake: add support for building and installing interfaces 2026-02-26 19:46:02 +00:00
b631fca0fd toolchain: add a program for compiling ipc interface definitions
ifc can be used to compile .if files into self-contained header-only C
libraries, which can be used to send/receive messages that conform
to the described interface.
2026-02-26 19:44:32 +00:00
47 changed files with 3901 additions and 362 deletions

View File

@@ -11,6 +11,7 @@ include(Meta)
include(Sysroot)
include(BSP)
include(Arch)
include(Msg-Interface)
include(Templates)
bsp_reset()
@@ -20,6 +21,7 @@ sysroot_set_base(
PATH ${CMAKE_SOURCE_DIR}/base)
add_subdirectory(kernel)
add_subdirectory(interface)
add_subdirectory(sys)
add_subdirectory(lib)
add_subdirectory(services)

75
cmake/Msg-Interface.cmake Normal file
View File

@@ -0,0 +1,75 @@
find_program(IFC
NAMES ifc
REQUIRED
HINTS ${BUILD_TOOLS_DIR})
message(STATUS "Found interface compiler: ${IFC}")
function(add_interface)
set(options)
set(one_value_args NAME PARENT_DIR PATH)
set(multi_value_args)
cmake_parse_arguments(PARSE_ARGV 0 arg
"${options}"
"${one_value_args}"
"${multi_value_args}")
message(STATUS "Building interface ${arg_NAME}")
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${arg_PARENT_DIR})
set(header_path ${CMAKE_CURRENT_BINARY_DIR}/${arg_PARENT_DIR}/${arg_NAME}.h)
add_custom_command(
OUTPUT ${header_path}
COMMAND ${IFC} ${arg_PATH}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${arg_PARENT_DIR}
COMMENT "Compiling interface: ${arg_NAME}")
add_custom_target(ifgen-${arg_NAME} ALL
DEPENDS ${header_path})
set_target_properties(ifgen-${arg_NAME} PROPERTIES
iface_header_path ${header_path}
iface_parent_dir ${arg_PARENT_DIR})
add_library(iflib-${arg_NAME} INTERFACE)
set_target_properties(iflib-${arg_NAME} PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR})
add_dependencies(iflib-${arg_NAME} ifgen-${arg_NAME})
add_library(interface::${arg_NAME} ALIAS iflib-${arg_NAME})
endfunction(add_interface)
function(iface_get_header_path)
set(options)
set(one_value_args NAME OUT)
set(multi_value_args)
cmake_parse_arguments(PARSE_ARGV 0 arg
"${options}"
"${one_value_args}"
"${multi_value_args}")
get_property(
value
TARGET ifgen-${name}
PROPERTY iface_header_path)
set(${arg_OUT} ${value} PARENT_SCOPE)
endfunction(iface_get_header_path)
function(iface_get_parent_dir)
set(options)
set(one_value_args NAME OUT)
set(multi_value_args)
cmake_parse_arguments(PARSE_ARGV 0 arg
"${options}"
"${one_value_args}"
"${multi_value_args}")
get_property(
value
TARGET ifgen-${name}
PROPERTY iface_parent_dir)
set(${arg_OUT} ${value} PARENT_SCOPE)
endfunction(iface_get_parent_dir)

View File

@@ -186,6 +186,37 @@ function(sysroot_add_file)
set_property(GLOBAL PROPERTY sysroot_target_list ${sysroot_targets} ${sysroot_target_name})
endfunction(sysroot_add_file)
function(sysroot_add_interface)
set(options)
set(one_value_args NAME DEST_DIR)
set(multi_value_args DEPENDS)
cmake_parse_arguments(PARSE_ARGV 0 arg
"${options}"
"${one_value_args}"
"${multi_value_args}")
iface_get_header_path(NAME ${arg_NAME} OUT src_path)
iface_get_parent_dir(NAME ${arg_NAME} OUT parent_dir)
set(dest_dir ${arg_DEST_DIR}/${parent_dir})
set(sysroot_target_name _sysroot-iface-${arg_NAME})
get_property(sysroot_targets GLOBAL PROPERTY sysroot_target_list)
list(LENGTH sysroot_targets nr_sysroot_targets)
if (${nr_sysroot_targets} GREATER 0)
math(EXPR serialiser_index "${nr_sysroot_targets}-1")
list(GET sysroot_targets ${serialiser_index} serialiser)
endif ()
add_custom_target(${sysroot_target_name}
COMMAND ${Python_EXECUTABLE} ${sysroot_tool}
add-binary ${sysroot_manifest} ${arg_NAME}
${dest_dir} ${src_path}
COMMENT "Preparing sysroot component: ${arg_ID}"
DEPENDS ifgen-${arg_NAME} ${serialiser} ${arg_DEPENDS})
set_property(GLOBAL PROPERTY sysroot_target_list ${sysroot_targets} ${sysroot_target_name})
endfunction(sysroot_add_interface)
function(sysroot_finalise)
get_property(sysroot_targets GLOBAL PROPERTY sysroot_target_list)

View File

@@ -10,7 +10,7 @@ fi
build_type=Debug
source_dir=$(realpath $(dirname "$0"))
native_build_dir=$source_dir/build-native
toolchain_build_dir=$source_dir/build/toolchain
target_build_dir=$source_dir/build
sysroot_dir=$target_build_dir/sysroot
@@ -19,25 +19,35 @@ if [ ! -d "$source_dir/arch/$target_arch" ]; then
exit -1
fi
rm -rf $native_build_dir $target_build_dir
mkdir -p $native_build_dir $target_build_dir
rm -rf $toolchain_build_dir $target_build_dir
mkdir -p $toolchain_build_dir $target_build_dir
pushd $native_build_dir > /dev/null
pushd $toolchain_build_dir > /dev/null
cmake \
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY="$native_build_dir/bin" \
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$native_build_dir/lib" \
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$native_build_dir/lib" \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DCMAKE_BUILD_TYPE=$build_type \
$source_dir/kernel/tools
$source_dir/toolchain
case $CMAKE_GENERATOR in
Ninja)
ninja
;;
"Unix Makefiles")
make
;;
*)
make
;;
esac
popd
pushd $target_build_dir > /dev/null
cmake \
-DBUILD_TOOLS_DIR=$native_build_dir/bin \
-DBUILD_TOOLS_DIR=$toolchain_build_dir/bin \
-DCMAKE_INSTALL_PREFIX=$sysroot_dir \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DTARGET_ARCH=$target_arch \
@@ -47,4 +57,9 @@ cmake \
-DCMAKE_SYSTEM_NAME=Rosetta \
-DCMAKE_TOOLCHAIN_FILE=$source_dir/arch/$target_arch/Platform/Rosetta.cmake
python3 \
$source_dir/util/merge-compiledb.py \
compile_commands.json \
toolchain/compile_commands.json
popd > /dev/null

7
interface/CMakeLists.txt Normal file
View File

@@ -0,0 +1,7 @@
file(GLOB if_files *.if)
foreach (file ${if_files})
get_filename_component(name ${file} NAME_WLE)
add_interface(NAME ${name} PATH ${file} PARENT_DIR rosetta)
sysroot_add_interface(NAME ${name} DEST_DIR /usr/include)
endforeach (file)

4
interface/fs.if Normal file
View File

@@ -0,0 +1,4 @@
interface fs {
msg open(string path, int flags) -> (int err);
msg uppercase(string old) -> (string new);
}

View File

@@ -1,21 +0,0 @@
file(GLOB sources
${CMAKE_CURRENT_SOURCE_DIR}/*.c)
file(GLOB headers
${CMAKE_CURRENT_SOURCE_DIR}/include/rosetta/msg/fs.h
${CMAKE_CURRENT_SOURCE_DIR}/*.h)
set(public_include_dirs
${CMAKE_CURRENT_SOURCE_DIR}/include)
rosetta_add_library(
NAME libmsg-fs STATIC
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
SOURCES ${sources}
HEADERS ${headers})
sysroot_add_library(
NAME libmsg-fs
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
target_link_libraries(libmsg-fs libmsg libmango ulibc)

View File

@@ -1,111 +0,0 @@
#include <rosetta/msg/fs.h>
#include <string.h>
kern_status_t rosetta_msg_fs_open_send(
kern_handle_t port,
const char *path,
int flags,
int *out_err)
{
size_t path_len = strlen(path);
struct rosetta_msg_fs_open msg = {0};
rosetta_msg_init(&msg.msg_base, ROSETTA_MSG_FS, ROSETTA_MSG_FS_OPEN);
uint16_t offset = sizeof msg;
msg.msg_request.o_path = offset;
msg.msg_request.o_path_len = path_len;
msg.msg_request.o_flags = flags;
struct iovec send_vec[] = {
IOVEC(&msg, sizeof msg),
IOVEC(path, path_len),
};
struct iovec reply_vec[] = {
IOVEC(&msg, sizeof msg),
};
struct msg req = {
.msg_data = send_vec,
.msg_data_count = sizeof send_vec / sizeof send_vec[0],
};
struct msg resp = {
.msg_data = reply_vec,
.msg_data_count = sizeof reply_vec / sizeof reply_vec[0],
};
kern_status_t status = msg_send(port, 0, &req, &resp);
if (status != KERN_OK) {
return status;
}
*out_err = msg.msg_response.o_err;
return KERN_OK;
}
kern_status_t rosetta_msg_fs_open_recv(
kern_handle_t channel,
msgid_t id,
struct rosetta_msg_string *out_path,
int *out_flags)
{
struct rosetta_msg_fs_open msg;
struct iovec vec = IOVEC(&msg, sizeof msg);
size_t r = 0;
kern_status_t status = msg_read(channel, id, 0, &vec, 1, &r);
if (status != KERN_OK) {
return status;
}
if (r != sizeof msg) {
/* TODO better error code for malformed messages */
return KERN_INVALID_ARGUMENT;
}
out_path->s_len = msg.msg_request.o_path_len;
if (out_path->s_max > 0) {
vec.io_base = (virt_addr_t)out_path->s_buf;
vec.io_len = out_path->s_max - 1;
if (vec.io_len > out_path->s_len) {
vec.io_len = out_path->s_len;
}
status = msg_read(
channel,
id,
msg.msg_request.o_path,
&vec,
1,
&r);
if (status != KERN_OK) {
return status;
}
if (r != out_path->s_len) {
return KERN_INVALID_ARGUMENT;
}
out_path->s_buf[out_path->s_len] = 0;
}
*out_flags = msg.msg_request.o_flags;
return KERN_OK;
}
kern_status_t rosetta_msg_fs_open_reply(
kern_handle_t channel,
msgid_t id,
int err)
{
struct rosetta_msg_fs_open msg = {0};
msg.msg_response.o_err = err;
struct iovec vec = IOVEC(&msg, sizeof msg);
struct msg kmsg = {.msg_data = &vec, .msg_data_count = 1};
return msg_reply(channel, 0, id, &kmsg);
}

View File

@@ -1,42 +0,0 @@
#ifndef ROSETTA_MSG_FS_H_
#define ROSETTA_MSG_FS_H_
#include <rosetta/msg.h>
/* rosetta.msg.fs protocol ID */
#define ROSETTA_MSG_FS 0x01409DD2U
/* rosetta.msg.fs.open message ID */
#define ROSETTA_MSG_FS_OPEN 0x7778U
struct rosetta_msg_fs_open {
struct rosetta_msg msg_base;
union {
struct {
uint16_t o_path;
uint16_t o_path_len;
uint16_t o_flags;
} msg_request;
struct {
int o_err;
} msg_response;
};
};
extern kern_status_t rosetta_msg_fs_open_send(
kern_handle_t port,
const char *path,
int flags,
int *out_err);
extern kern_status_t rosetta_msg_fs_open_recv(
kern_handle_t channel,
msgid_t id,
struct rosetta_msg_string *out_path,
int *out_flags);
extern kern_status_t rosetta_msg_fs_open_reply(
kern_handle_t channel,
msgid_t id,
int err);
#endif

View File

@@ -1,21 +0,0 @@
file(GLOB sources
${CMAKE_CURRENT_SOURCE_DIR}/*.c)
file(GLOB headers
${CMAKE_CURRENT_SOURCE_DIR}/include/rosetta/msg/ld.h
${CMAKE_CURRENT_SOURCE_DIR}/*.h)
set(public_include_dirs
${CMAKE_CURRENT_SOURCE_DIR}/include)
rosetta_add_library(
NAME libmsg-ld STATIC
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
SOURCES ${sources}
HEADERS ${headers})
sysroot_add_library(
NAME libmsg-ld
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
target_link_libraries(libmsg-ld libmsg libmango)

View File

@@ -1,26 +0,0 @@
#ifndef ROSETTA_MSG_LD_H_
#define ROSETTA_MSG_LD_H_
#include <rosetta/msg.h>
/* rosetta.msg.ld protocol ID */
#define ROSETTA_MSG_LD 0x5563D896U
/* rosetta.msg.ld.get-object message ID */
#define ROSETTA_MSG_LD_GET_OBJECT 1
struct rosetta_msg_ld_get_object {
struct rosetta_msg msg_base;
union {
struct {
uint16_t go_object_name;
} msg_request;
struct {
int go_err;
uint16_t go_object_index;
} msg_response;
};
};
#endif

View File

@@ -1,3 +0,0 @@
void msg_ld_tmp(void)
{
}

View File

@@ -1,21 +0,0 @@
file(GLOB sources
${CMAKE_CURRENT_SOURCE_DIR}/*.c)
file(GLOB headers
${CMAKE_CURRENT_SOURCE_DIR}/include/rosetta/msg.h
${CMAKE_CURRENT_SOURCE_DIR}/*.h)
set(public_include_dirs
${CMAKE_CURRENT_SOURCE_DIR}/include)
rosetta_add_library(
NAME libmsg STATIC
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
SOURCES ${sources}
HEADERS ${headers})
sysroot_add_library(
NAME libmsg
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
target_link_libraries(libmsg libmango ulibc)

View File

@@ -1,31 +0,0 @@
#ifndef ROSETTA_MSG_H_
#define ROSETTA_MSG_H_
#define ROSETTA_MSG_MAGIC 0x9AB07D10U
#include <mango/msg.h>
#include <stdint.h>
struct rosetta_msg {
uint32_t msg_magic;
uint32_t msg_protocol;
uint16_t msg_id;
uint16_t msg_reserved;
};
struct rosetta_msg_string {
char *s_buf;
size_t s_len;
size_t s_max;
};
extern void rosetta_msg_init(
struct rosetta_msg *msg,
uint32_t protocol_id,
uint16_t msg_id);
extern kern_status_t rosetta_msg_recv(
kern_handle_t channel,
msgid_t *out_id,
struct rosetta_msg *out_msg);
#endif

View File

@@ -1,33 +0,0 @@
#include <rosetta/msg.h>
#include <string.h>
void rosetta_msg_init(
struct rosetta_msg *msg,
uint32_t protocol_id,
uint16_t msg_id)
{
memset(msg, 0x0, sizeof *msg);
msg->msg_magic = ROSETTA_MSG_MAGIC;
msg->msg_protocol = protocol_id;
msg->msg_id = msg_id;
}
kern_status_t rosetta_msg_recv(
kern_handle_t channel,
msgid_t *out_id,
struct rosetta_msg *out_msg)
{
struct iovec iov = IOVEC(out_msg, sizeof *out_msg);
struct msg kmsg = MSG(&iov, 1, NULL, 0);
kern_status_t status = msg_recv(channel, 0, out_id, &kmsg);
if (status != KERN_OK) {
return status;
}
if (out_msg->msg_magic != ROSETTA_MSG_MAGIC) {
return KERN_INVALID_ARGUMENT;
}
return KERN_OK;
}

View File

@@ -5,7 +5,7 @@ set_property(SOURCE ${arch_sources} PROPERTY LANGUAGE C)
add_executable(bootstrap ${c_sources} ${arch_sources})
target_link_libraries(bootstrap libmango ulibc liblaunch libmsg-fs)
target_link_libraries(bootstrap libmango ulibc liblaunch interface::fs)
target_compile_options(bootstrap PRIVATE
-fPIC -pie -fno-stack-protector -nostdlib -ffreestanding)

View File

@@ -6,10 +6,12 @@
.extern main
.type main, @function
.extern exit
.type exit, @function
.extern task_exit
.type task_exit, @function
_start:
call main
mov %rax, %rdi
call task_exit
1: pause
jmp 1b

View File

@@ -1,3 +1,5 @@
#define MSG_IMPLEMENTATION
#define MSG_NO_MALLOC
#include "tar.h"
#include <launch.h>
@@ -5,8 +7,7 @@
#include <mango/msg.h>
#include <mango/task.h>
#include <mango/types.h>
#include <rosetta/msg.h>
#include <rosetta/msg/fs.h>
#include <rosetta/fs.h>
#include <stdint.h>
#include <stdio.h>
@@ -46,6 +47,31 @@ static enum launch_status resolve_dependency(
return LAUNCH_OK;
}
static kern_status_t open(const char *path, int flags, int *out_err)
{
kern_logf("received msg: open(%s, %d)", path, flags);
*out_err = 13;
return KERN_OK;
}
static kern_status_t uppercase(const char *old, struct msg_string *new)
{
kern_logf("received msg: uppercase(%s)", old);
size_t i;
for (i = 0; old[i] && i < new->str_max - 1; i++) {
char c = old[i];
if (c >= 'a' && c <= 'z') {
new->str_buf[i] = old[i] - 'a' + 'A';
} else {
new->str_buf[i] = old[i];
}
}
new->str_len = i - 1;
new->str_buf[i] = 0;
return KERN_OK;
}
int main(
int argc,
const char **argv,
@@ -98,48 +124,29 @@ int main(
= launch_ctx_execute(&launch, &params, LAUNCH_F_NONE, &result);
kern_logf("launch result: %d", status);
const struct fs_vtable fs_vtable = {
.open = open,
.uppercase = uppercase,
};
#if 1
while (1) {
msgid_t id;
struct rosetta_msg msg;
kern_status_t status = rosetta_msg_recv(channel, &id, &msg);
struct msg_header hdr;
kern_status_t status = msg_recv_generic(channel, &id, &hdr);
if (status != KERN_OK) {
kern_logf("message recv error %d", status);
continue;
}
if (msg.msg_protocol != ROSETTA_MSG_FS) {
if (hdr.hdr_protocol != PROTOCOL_FS) {
kern_logf(
"unknown message protocol %u",
msg.msg_protocol);
hdr.hdr_protocol);
continue;
}
if (msg.msg_id != ROSETTA_MSG_FS_OPEN) {
kern_logf("unknown message function %u", msg.msg_id);
continue;
}
char path[4096];
int flags;
struct rosetta_msg_string path_str = {
.s_buf = path,
.s_max = sizeof path,
};
status = rosetta_msg_fs_open_recv(
channel,
id,
&path_str,
&flags);
if (status != KERN_OK) {
kern_logf("rosetta.fs.open recv error %d", status);
continue;
}
kern_logf("open(%s, %d)", path, flags);
rosetta_msg_fs_open_reply(channel, id, 0);
status = fs_dispatch(channel, &fs_vtable, id, &hdr);
}
#endif

View File

@@ -9,7 +9,7 @@ set_target_properties(ld PROPERTIES
OUTPUT_NAME "ld64"
SUFFIX ".so")
target_link_libraries(ld ulibc libmango libmsg-fs)
target_link_libraries(ld ulibc libmango interface::fs)
target_compile_options(ld PRIVATE
-fPIC -fno-stack-protector -nostdlib -ffreestanding)

View File

@@ -6,10 +6,12 @@
.extern main
.type main, @function
.extern exit
.type exit, @function
.extern task_exit
.type task_exit, @function
_start:
call main
mov %rax, %rdi
call task_exit
1: pause
jmp 1b

View File

@@ -1,7 +1,9 @@
#define MSG_IMPLEMENTATION
#include <mango/log.h>
#include <mango/msg.h>
#include <mango/types.h>
#include <rosetta/msg/fs.h>
#include <rosetta/fs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -14,7 +16,6 @@ int main(
kern_handle_t address_space,
uintptr_t bsp_base)
{
kern_log("ld!");
void *brk = sbrk(0);
kern_logf("brk=%p", brk);
@@ -36,19 +37,24 @@ int main(
#if 1
port_connect(port, 0, 0);
const char *str = "hello";
char new_buf[512] = {0};
struct msg_string new = {.str_buf = new_buf, .str_max = sizeof new_buf};
kern_logf("sending msg: uppercase(%s)", str);
status = fs_uppercase(port, str, &new);
kern_logf("uppercase(%s) = %s", str, new_buf);
const char *path = "/usr/lib/libc.so";
int flags = 4;
int err = 0;
kern_logf("calling open(%s, %d)", path, flags);
status = rosetta_msg_fs_open_send(port, path, flags, &err);
kern_logf("sending msg: open(%s, %d)", path, flags);
status = fs_open(port, path, flags, &err);
if (status != KERN_OK) {
kern_logf("open call failed (status %d)", status);
} else if (err != 0) {
kern_logf("open call returned error %d", err);
} else {
kern_logf("open call succeeded");
} else {
kern_logf("open(%s, %d) = %d", path, flags, err);
}
#endif

17
toolchain/CMakeLists.txt Normal file
View File

@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.14)
project(rosetta-toolchain C CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
find_package(Bluelib REQUIRED COMPONENTS Core Ds Term Cmd Io)
add_subdirectory(
../kernel/tools
${CMAKE_CURRENT_BINARY_DIR}/kernel-tools)
add_subdirectory(ifc)

View File

@@ -0,0 +1,212 @@
#[=======================================================================[.rst:
FindBluelib
------------
Find the Bluelib library and header directories
Imported Targets
^^^^^^^^^^^^^^^^
This module defines the following :prop_tgt:`IMPORTED` target:
``Bluelib::Bluelib``
The Bluelib library, if found
Result Variables
^^^^^^^^^^^^^^^^
This module will set the following variables in your project:
``Bluelib_FOUND``
true if the Bluelib C headers and libraries were found
``Bluelib_INCLUDE_DIR``
directories containing the Bluelib C headers.
``Bluelib_LIBRARY``
the C library to link against
Hints
^^^^^
The user may set the environment variable ``Bluelib_PREFIX`` to the root
directory of a Bluelib library installation.
#]=======================================================================]
set (Bluelib_SEARCH_PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr/local/share
/usr
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
${Bluelib_PREFIX}
$ENV{Bluelib_PREFIX})
if (Bluelib_STATIC)
set(_lib_suffix "-s")
endif ()
set(supported_components
Core Ds Term Cmd Io Serial Compress
Core-MM)
set(components ${Bluelib_FIND_COMPONENTS})
string(REPLACE ";" ", " supported_components_string_list "${supported_components}")
if (NOT components)
set(components ${supported_components})
endif ()
set(required_vars)
foreach (component ${components})
if (NOT "${component}" IN_LIST supported_components)
message(FATAL_ERROR "'${component}' is not a valid Bluelib module.\nSupported modules: ${supported_components_string_list}")
endif ()
string(TOLOWER ${component} header_name)
string(REPLACE "-mm" "" header_name "${header_name}")
string(TOLOWER ${component} lib_name)
set(lib_name ${lib_name}${_lib_suffix})
set(cmake_lib_name ${component})
string(REPLACE "-" "_" cmake_lib_name "${cmake_lib_name}")
if (NOT Bluelib_${cmake_lib_dir}_INCLUDE_DIR)
find_path(Bluelib_${cmake_lib_name}_INCLUDE_DIR
NAMES blue/${header_name}.h blue/${header_name}.hpp
${Bluelib_FIND_ARGS}
PATH_SUFFIXES include
PATHS ${Bluelib_SEARCH_PATHS})
endif ()
if (NOT Bluelib_${cmake_lib_dir}_LIBRARY)
find_library(Bluelib_${cmake_lib_name}_LIBRARY
NAMES blue-${lib_name} ${Bluelib_FIND_ARGS}
PATH_SUFFIXES lib
PATHS ${Bluelib_SEARCH_PATHS})
else ()
# on Windows, ensure paths are in canonical format (forward slahes):
file(TO_CMAKE_PATH "${Bluelib_${cmake_lib_name}_LIBRARY}" Bluelib_${cmake_lib_name}_LIBRARY)
endif()
list(APPEND required_vars Bluelib_${cmake_lib_name}_INCLUDE_DIR Bluelib_${cmake_lib_name}_LIBRARY)
endforeach (component)
unset(Bluelib_FIND_ARGS)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Bluelib
REQUIRED_VARS ${required_vars})
if (Bluelib_FOUND)
set(created_targets)
foreach (component ${components})
string(TOLOWER ${component} header_name)
string(REPLACE "-mm" "" header_name "${header_name}")
string(TOLOWER ${component} lib_name)
set(lib_name ${lib_name}${_lib_suffix})
set(cmake_lib_name ${component})
string(REPLACE "-" "_" cmake_lib_name "${cmake_lib_name}")
if(NOT TARGET Bluelib::${component})
add_library(Bluelib::${component} UNKNOWN IMPORTED)
set_target_properties(Bluelib::${component} PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Bluelib_${cmake_lib_name}_INCLUDE_DIR}")
target_compile_definitions(Bluelib::${component} INTERFACE _CRT_SECURE_NO_WARNINGS=1)
if (Bluelib_STATIC)
target_compile_definitions(Bluelib::${component} INTERFACE BLUELIB_STATIC=1)
endif ()
set_target_properties(Bluelib::${component} PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_LOCATION "${Bluelib_${cmake_lib_name}_LIBRARY}")
set(created_targets ${created_targets} ${component})
endif ()
endforeach (component)
foreach (component ${created_targets})
if ("${component}" STREQUAL "Ds")
if (NOT TARGET Bluelib::Core)
message(FATAL_ERROR "Bluelib: Module 'Ds' depends on 'Core', which was not specified in find_package()")
endif ()
target_link_libraries(Bluelib::Ds INTERFACE Bluelib::Core)
endif ()
if ("${component}" STREQUAL "Term")
if (NOT TARGET Bluelib::Core)
message(FATAL_ERROR "Bluelib: Module 'Term' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET Bluelib::Ds)
message(FATAL_ERROR "Bluelib: Module 'Term' depends on 'Ds', which was not specified in find_package()")
endif ()
target_link_libraries(Bluelib::Term INTERFACE Bluelib::Core Bluelib::Ds)
endif ()
if ("${component}" STREQUAL "Serial")
if (NOT TARGET Bluelib::Core)
message(FATAL_ERROR "Bluelib: Module 'Serial' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET Bluelib::Ds)
message(FATAL_ERROR "Bluelib: Module 'Serial' depends on 'Ds', which was not specified in find_package()")
endif ()
target_link_libraries(Bluelib::Serial INTERFACE Bluelib::Core Bluelib::Ds)
endif ()
if ("${component}" STREQUAL "Cmd")
if (NOT TARGET Bluelib::Core)
message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET Bluelib::Ds)
message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Ds', which was not specified in find_package()")
endif ()
if (NOT TARGET Bluelib::Term)
message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Term', which was not specified in find_package()")
endif ()
target_link_libraries(Bluelib::Cmd INTERFACE Bluelib::Core Bluelib::Ds Bluelib::Term)
endif ()
if ("${component}" STREQUAL "Io")
if (NOT TARGET Bluelib::Core)
message(FATAL_ERROR "Bluelib: Module 'Io' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET Bluelib::Ds)
message(FATAL_ERROR "Bluelib: Module 'Io' depends on 'Ds', which was not specified in find_package()")
endif ()
target_link_libraries(Bluelib::Io INTERFACE Bluelib::Core Bluelib::Ds)
endif ()
if ("${component}" STREQUAL "Compress")
if (NOT TARGET Bluelib::Core)
message(FATAL_ERROR "Bluelib: Module 'Compress' depends on 'Core', which was not specified in find_package()")
endif ()
target_link_libraries(Bluelib::Compress INTERFACE Bluelib::Core Bluelib::Ds)
endif ()
if ("${component}" STREQUAL "Core-MM")
if (NOT TARGET Bluelib::Core)
message(FATAL_ERROR "Bluelib: Module 'Core-MM' depends on 'Core', which was not specified in find_package()")
endif ()
target_link_libraries(Bluelib::Core-MM INTERFACE Bluelib::Core)
endif ()
endforeach (component)
endif()

View File

@@ -0,0 +1,7 @@
file(GLOB sources
*.c *.h
backend/c-mpc/*.c backend/c-mpc/*.h)
add_executable(ifc ${sources})
target_link_libraries(ifc Bluelib::Core Bluelib::Ds Bluelib::Cmd Bluelib::Io)

13
toolchain/ifc/backend.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef IFC_BACKEND_H_
#define IFC_BACKEND_H_
struct interface_definition;
struct backend {
const char *b_name;
int (*b_emit)(const struct interface_definition *);
};
extern const struct backend *c_mpc_backend(void);
#endif

File diff suppressed because it is too large Load Diff

52
toolchain/ifc/ctx.c Normal file
View File

@@ -0,0 +1,52 @@
#include "ctx.h"
#include <stdlib.h>
#include <string.h>
static void init_builtin_types(struct ctx *ctx)
{
for (size_t i = 0; i < TYPE_OTHER; i++) {
ctx->ctx_builtin_types[i].ty_id = i;
}
}
struct ctx *ctx_create(void)
{
struct ctx *out = malloc(sizeof *out);
if (!out) {
return NULL;
}
memset(out, 0x0, sizeof *out);
init_builtin_types(out);
return out;
}
void ctx_destroy(struct ctx *ctx)
{
free(ctx);
}
const struct type *ctx_get_type(struct ctx *ctx, const char *name)
{
if (!strcmp(name, "string")) {
return ctx_get_builtin_type(ctx, TYPE_STRING);
}
if (!strcmp(name, "int")) {
return ctx_get_builtin_type(ctx, TYPE_INT);
}
return NULL;
}
const struct type *ctx_get_builtin_type(struct ctx *ctx, enum type_id id)
{
if (id >= TYPE_OTHER) {
return NULL;
}
return &ctx->ctx_builtin_types[id];
}

18
toolchain/ifc/ctx.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef IFC_CTX_H_
#define IFC_CTX_H_
#include "type.h"
struct ctx {
struct type ctx_builtin_types[TYPE_OTHER];
};
extern struct ctx *ctx_create(void);
extern void ctx_destroy(struct ctx *ctx);
extern const struct type *ctx_get_type(struct ctx *ctx, const char *name);
extern const struct type *ctx_get_builtin_type(
struct ctx *ctx,
enum type_id id);
#endif

12
toolchain/ifc/file-span.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef IFC_FILE_SPAN_H_
#define IFC_FILE_SPAN_H_
struct file_cell {
unsigned int c_row, c_col;
};
struct file_span {
struct file_cell s_start, s_end;
};
#endif

60
toolchain/ifc/interface.c Normal file
View File

@@ -0,0 +1,60 @@
#include "interface.h"
#include "msg.h"
#include <blue/ds/string.h>
#include <stdlib.h>
#include <string.h>
struct interface_definition *interface_definition_create(const char *name)
{
struct interface_definition *out = malloc(sizeof *out);
if (!out) {
return NULL;
}
memset(out, 0x0, sizeof *out);
out->if_name = b_strdup(name);
return out;
}
void interface_definition_destroy(struct interface_definition *iface)
{
b_queue_entry *entry = b_queue_pop_front(&iface->if_msg);
while (entry) {
struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
msg_definition_destroy(msg);
entry = b_queue_pop_front(&iface->if_msg);
}
free(iface->if_name);
free(iface);
}
bool interface_definition_has_msg(
const struct interface_definition *iface,
const char *name)
{
b_queue_entry *entry = b_queue_first(&iface->if_msg);
while (entry) {
struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
if (!strcmp(msg->msg_name, name)) {
return true;
}
entry = b_queue_next(entry);
}
return false;
}
void interface_definition_add_msg(
struct interface_definition *iface,
struct msg_definition *msg)
{
b_queue_push_back(&iface->if_msg, &msg->msg_entry);
}

24
toolchain/ifc/interface.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef IFC_INTERFACE_H_
#define IFC_INTERFACE_H_
#include <blue/core/queue.h>
struct msg_definition;
struct interface_definition {
char *if_name;
b_queue if_msg;
};
extern struct interface_definition *interface_definition_create(
const char *name);
extern void interface_definition_destroy(struct interface_definition *iface);
extern bool interface_definition_has_msg(
const struct interface_definition *iface,
const char *name);
extern void interface_definition_add_msg(
struct interface_definition *iface,
struct msg_definition *msg);
#endif

740
toolchain/ifc/lex.c Normal file
View File

@@ -0,0 +1,740 @@
#include "lex.h"
#include "line-source.h"
#include "token.h"
#include <blue/core/hash.h>
#include <blue/core/misc.h>
#include <blue/core/queue.h>
#include <blue/ds/dict.h>
#include <blue/ds/number.h>
#include <blue/ds/string.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wctype.h>
#define LINEBUF_DEFAULT_CAPACITY 1024
#define LEX_TOKEN_DEF(i, n) {.id = (i), .name = (n)}
#define IS_VALID_IDENT_CHAR(c) \
(b_wchar_is_alnum(c) || c == '.' || c == '-' || c == '_')
#define IS_VALID_IDENT_START_CHAR(c) \
(b_wchar_is_alpha(c) || c == '.' || c == '_')
#define IS_VALID_REG_START_CHAR(c) (b_wchar_is_alnum(c) || c == '.' || c == '_')
static struct lex_token_def symbols[] = {
LEX_TOKEN_DEF(SYM_COMMA, ","),
LEX_TOKEN_DEF(SYM_HYPHEN, "-"),
LEX_TOKEN_DEF(SYM_LEFT_BRACE, "{"),
LEX_TOKEN_DEF(SYM_RIGHT_BRACE, "}"),
LEX_TOKEN_DEF(SYM_LEFT_PAREN, "("),
LEX_TOKEN_DEF(SYM_RIGHT_PAREN, ")"),
LEX_TOKEN_DEF(SYM_SEMICOLON, ";"),
LEX_TOKEN_DEF(SYM_HYPHEN_RIGHT_ANGLE, "->"),
};
static const size_t nr_symbols = sizeof symbols / sizeof symbols[0];
static struct lex_token_def keywords[] = {
LEX_TOKEN_DEF(KW_INTERFACE, "interface"),
LEX_TOKEN_DEF(KW_MSG, "msg"),
};
static const size_t nr_keywords = sizeof keywords / sizeof keywords[0];
static struct lex_symbol_node *get_symbol_node(
struct lex_symbol_node *node,
char c)
{
b_queue_entry *entry = b_queue_first(&node->s_children);
while (entry) {
struct lex_symbol_node *child
= b_unbox(struct lex_symbol_node, entry, s_entry);
if (child->s_char == c) {
return child;
}
entry = b_queue_next(entry);
}
return NULL;
}
static b_string *get_temp_string(struct lex *lex)
{
if (!lex->lex_temp) {
lex->lex_temp = b_string_create();
}
b_string_clear(lex->lex_temp);
return lex->lex_temp;
}
static enum status put_symbol(
struct lex_symbol_node *tree,
struct lex_token_def *sym)
{
for (size_t i = 0; sym->name[i]; i++) {
char c = sym->name[i];
struct lex_symbol_node *child = get_symbol_node(tree, c);
if (child) {
tree = child;
continue;
}
child = malloc(sizeof *child);
if (!child) {
return ERR_NO_MEMORY;
}
memset(child, 0x0, sizeof *child);
child->s_def = NULL;
child->s_char = c;
b_queue_push_back(&tree->s_children, &child->s_entry);
tree = child;
}
tree->s_def = sym;
return SUCCESS;
}
static void destroy_symbol_tree(struct lex_symbol_node *tree)
{
b_queue_entry *entry = b_queue_first(&tree->s_children);
while (entry) {
struct lex_symbol_node *node
= b_unbox(struct lex_symbol_node, entry, s_entry);
b_queue_entry *next = b_queue_next(entry);
b_queue_delete(&tree->s_children, entry);
destroy_symbol_tree(node);
entry = next;
}
free(tree);
}
static struct lex_symbol_node *build_symbol_tree(void)
{
struct lex_symbol_node *root = malloc(sizeof *root);
if (!root) {
return NULL;
}
memset(root, 0x0, sizeof *root);
root->s_def = NULL;
enum status status = SUCCESS;
for (size_t i = 0; i < nr_symbols; i++) {
status = put_symbol(root, &symbols[i]);
if (status != SUCCESS) {
destroy_symbol_tree(root);
return NULL;
}
}
return root;
}
struct lex *lex_create(struct line_source *src)
{
struct lex *lex = malloc(sizeof *lex);
if (!lex) {
return NULL;
}
memset(lex, 0x0, sizeof *lex);
lex->lex_status = SUCCESS;
lex->lex_source = src;
lex->lex_sym_tree = build_symbol_tree();
if (!lex->lex_sym_tree) {
lex_destroy(lex);
return NULL;
}
return lex;
}
void lex_destroy(struct lex *lex)
{
b_queue_entry *entry = b_queue_first(&lex->lex_queue);
while (entry) {
struct token *tok = b_unbox(struct token, entry, tok_entry);
b_queue_entry *next = b_queue_next(entry);
b_queue_delete(&lex->lex_queue, entry);
token_destroy(tok);
entry = next;
}
if (lex->lex_sym_tree) {
destroy_symbol_tree(lex->lex_sym_tree);
}
if (lex->lex_temp) {
b_string_unref(lex->lex_temp);
}
free(lex);
}
enum status lex_get_status(const struct lex *lex)
{
return lex->lex_status;
}
struct line_source *lex_get_line_source(const struct lex *lex)
{
return lex->lex_source;
}
const struct file_cell *lex_get_cursor(const struct lex *lex)
{
return &lex->lex_source->s_cursor;
}
static bool char_can_begin_symbol(char c)
{
for (size_t i = 0; i < nr_symbols; i++) {
if (symbols[i].name[0] == c) {
return true;
}
}
return false;
}
static struct token *create_token(enum token_type type)
{
struct token *tok = malloc(sizeof *tok);
if (!tok) {
return NULL;
}
memset(tok, 0x0, sizeof *tok);
tok->tok_type = type;
return tok;
}
static void set_token_start(struct lex *lex)
{
lex->lex_token_start = *line_source_get_cursor(lex->lex_source);
}
static void set_token_end(struct lex *lex)
{
lex->lex_token_end = *line_source_get_cursor(lex->lex_source);
}
static enum status push_token(struct lex *lex, struct token *tok)
{
tok->tok_location.s_start = lex->lex_token_start;
tok->tok_location.s_end = lex->lex_token_end;
b_queue_push_back(&lex->lex_queue, &tok->tok_entry);
return SUCCESS;
}
static enum status push_symbol(struct lex *lex, enum token_symbol sym)
{
struct token *tok = malloc(sizeof *tok);
if (!tok) {
return ERR_NO_MEMORY;
}
memset(tok, 0x0, sizeof *tok);
tok->tok_type = TOK_SYMBOL;
tok->tok_value_type = TOK_V_SYMBOL;
tok->tok_sym = sym;
return push_token(lex, tok);
}
static enum status push_keyword(struct lex *lex, enum token_keyword kw)
{
struct token *tok = malloc(sizeof *tok);
if (!tok) {
return ERR_NO_MEMORY;
}
memset(tok, 0x0, sizeof *tok);
tok->tok_type = TOK_KEYWORD;
tok->tok_value_type = TOK_V_KEYWORD;
tok->tok_kw = kw;
return push_token(lex, tok);
}
static enum status push_string_token(
struct lex *lex,
enum token_type type,
char *s)
{
struct token *tok = malloc(sizeof *tok);
if (!tok) {
return ERR_NO_MEMORY;
}
char *ep = NULL;
long long v = strtoll(s, &ep, 10);
memset(tok, 0x0, sizeof *tok);
tok->tok_type = type;
if (*ep == '\0') {
tok->tok_int = v;
tok->tok_value_type = TOK_V_INT;
free(s);
} else {
tok->tok_str = s;
tok->tok_value_type = TOK_V_STRING;
}
return push_token(lex, tok);
}
static enum status push_int(struct lex *lex, unsigned long long v)
{
struct token *tok = malloc(sizeof *tok);
if (!tok) {
return ERR_NO_MEMORY;
}
memset(tok, 0x0, sizeof *tok);
tok->tok_type = TOK_INT;
tok->tok_value_type = TOK_V_INT;
tok->tok_int = v;
return push_token(lex, tok);
}
static enum status read_line_comment(struct lex *lex)
{
while (true) {
b_wchar c = line_source_getc(lex->lex_source);
if (c == -ERR_EOF || c == '\n') {
break;
}
if (c < 0) {
return -c;
}
}
return SUCCESS;
}
static enum status read_number(struct lex *lex, bool negate)
{
int token_len = 0;
int base = 10;
int dots = 0;
b_string *str = get_temp_string(lex);
if (!negate) {
set_token_start(lex);
}
while (true) {
b_wchar c = line_source_peekc(lex->lex_source);
if (c == -ERR_EOF) {
break;
}
if (c < 0) {
return -c;
}
if (c == '_') {
token_len++;
set_token_end(lex);
line_source_getc(lex->lex_source);
continue;
}
if (c == '.') {
return ERR_BAD_SYNTAX;
}
if (b_wchar_is_space(c) || b_wchar_is_punct(c)) {
break;
}
if (c == 'x' && token_len == 1) {
base = 16;
token_len++;
set_token_end(lex);
line_source_getc(lex->lex_source);
continue;
}
if (c == 'b' && token_len == 1) {
base = 2;
token_len++;
set_token_end(lex);
line_source_getc(lex->lex_source);
continue;
}
if (base == 2 && c != '0' && c != '1') {
return ERR_BAD_SYNTAX;
}
if (base == 10 && !isdigit(c)) {
return ERR_BAD_SYNTAX;
}
if (base == 16 && !isxdigit(c)) {
return ERR_BAD_SYNTAX;
}
b_string_append_wc(str, c);
set_token_end(lex);
line_source_getc(lex->lex_source);
token_len++;
}
if (token_len == 1 && base == 7) {
return push_int(lex, 0);
}
const char *s = b_string_ptr(str);
char *ep = NULL;
/* negative numbers will be lexed as a hyphen followed by a positive
* number. */
unsigned long long v = strtoull(s, &ep, base);
if (*ep != '\0') {
return ERR_BAD_SYNTAX;
}
if (negate) {
v *= -1;
}
return push_int(lex, v);
}
static enum token_keyword find_keyword(const char *s)
{
for (size_t i = 0; i < nr_keywords; i++) {
if (!strcmp(keywords[i].name, s)) {
return keywords[i].id;
}
}
return KW_NONE;
}
static enum status read_ident(struct lex *lex, enum token_type type)
{
int dots = 0;
b_string *str = get_temp_string(lex);
b_wchar prev = 0;
if (type == TOK_NONE) {
set_token_start(lex);
}
while (1) {
b_wchar c = line_source_peekc(lex->lex_source);
if ((c == '.' || c == '-') && prev == c) {
return ERR_BAD_SYNTAX;
}
if (c == '.') {
dots++;
}
if (!IS_VALID_IDENT_CHAR(c)) {
break;
}
prev = c;
b_string_append_wc(str, c);
set_token_end(lex);
line_source_getc(lex->lex_source);
}
if (type == TOK_NONE) {
type = dots > 0 ? TOK_NAME : TOK_WORD;
}
char *s = b_string_steal(str);
enum token_keyword kw = find_keyword(s);
if (kw != KW_NONE) {
free(s);
return push_keyword(lex, kw);
}
return push_string_token(lex, type, s);
}
static enum status read_string(struct lex *lex)
{
b_string *str = get_temp_string(lex);
b_wchar c = line_source_peekc(lex->lex_source);
bool esc = false;
if (c != '"') {
return ERR_BAD_SYNTAX;
}
line_source_getc(lex->lex_source);
while (1) {
b_wchar c = line_source_peekc(lex->lex_source);
if (esc) {
switch (c) {
case '\\':
case '"':
b_string_append_wc(str, c);
break;
default:
return ERR_BAD_SYNTAX;
}
esc = false;
line_source_getc(lex->lex_source);
continue;
}
if (c == '\\') {
esc = true;
line_source_getc(lex->lex_source);
continue;
}
if (c == '"') {
line_source_getc(lex->lex_source);
break;
}
b_string_append_wc(str, c);
line_source_getc(lex->lex_source);
}
char *s = b_string_steal(str);
return push_string_token(lex, TOK_STRING, s);
}
static enum status read_symbol(struct lex *lex)
{
struct lex_symbol_node *node = lex->lex_sym_tree;
set_token_start(lex);
b_wchar prev = 0;
while (true) {
b_wchar c = line_source_peekc(lex->lex_source);
if (c < 0) {
break;
}
struct lex_symbol_node *next = get_symbol_node(node, c);
if (!next) {
prev = c;
break;
}
node = next;
set_token_end(lex);
line_source_getc(lex->lex_source);
prev = c;
}
if (!node || node->s_def == NULL) {
return ERR_BAD_SYNTAX;
}
if (node->s_def->id == SYM_HYPHEN && isdigit(prev)) {
return read_number(lex, true);
}
return push_symbol(lex, node->s_def->id);
}
static void skip_whitespace(struct lex *lex)
{
b_wchar c = line_source_peekc(lex->lex_source);
while (b_wchar_is_space(c)) {
line_source_getc(lex->lex_source);
c = line_source_peekc(lex->lex_source);
}
}
static bool should_skip(b_wchar c, bool skip_linefeeds)
{
bool skip = b_wchar_is_space(c);
if (!skip_linefeeds) {
skip = (skip && c != '\n');
}
return skip;
}
static void skip_ignored_chars(struct lex *lex, bool include_linefeeds)
{
b_wchar c = line_source_peekc(lex->lex_source);
while (1) {
while (should_skip(c, include_linefeeds)) {
line_source_getc(lex->lex_source);
c = line_source_peekc(lex->lex_source);
}
if (c != '#') {
break;
}
line_source_getc(lex->lex_source);
c = line_source_peekc(lex->lex_source);
while (c != '\n') {
line_source_getc(lex->lex_source);
c = line_source_peekc(lex->lex_source);
}
line_source_getc(lex->lex_source);
c = line_source_peekc(lex->lex_source);
}
}
static enum status pump_tokens(struct lex *lex)
{
b_wchar c = line_source_peekc(lex->lex_source);
if (c < 0) {
return -c;
}
while (1) {
if (c == '#' || (b_wchar_is_space(c) && c != '\n')) {
skip_ignored_chars(lex, false);
} else {
break;
}
c = line_source_peekc(lex->lex_source);
}
if (c == '\\') {
line_source_getc(lex->lex_source);
skip_ignored_chars(lex, true);
c = line_source_peekc(lex->lex_source);
}
if (c == '\n') {
set_token_start(lex);
set_token_end(lex);
while (c == '\n') {
line_source_getc(lex->lex_source);
if (!line_source_input_available(lex->lex_source)) {
break;
}
c = line_source_peekc(lex->lex_source);
}
if (c < 0) {
return -c;
}
return SUCCESS;
}
while (b_wchar_is_space(c) && c != '\n') {
line_source_getc(lex->lex_source);
c = line_source_peekc(lex->lex_source);
}
if (IS_VALID_IDENT_START_CHAR(c)) {
return read_ident(lex, TOK_NONE);
}
if (char_can_begin_symbol(c)) {
return read_symbol(lex);
}
if (c == '"') {
return read_string(lex);
}
if (isdigit(c)) {
return read_number(lex, false);
}
return ERR_BAD_SYNTAX;
}
struct token *lex_peek(struct lex *lex)
{
enum status status = SUCCESS;
while (b_queue_empty(&lex->lex_queue)) {
status = pump_tokens(lex);
if (status != SUCCESS) {
lex->lex_status = status;
return NULL;
}
}
lex->lex_status = status;
b_queue_entry *entry = b_queue_first(&lex->lex_queue);
struct token *tok = b_unbox(struct token, entry, tok_entry);
return tok;
}
void lex_advance(struct lex *lex)
{
enum status status = SUCCESS;
while (b_queue_empty(&lex->lex_queue)) {
status = pump_tokens(lex);
if (status != SUCCESS) {
lex->lex_status = status;
return;
}
}
b_queue_entry *entry = b_queue_pop_front(&lex->lex_queue);
struct token *tok = b_unbox(struct token, entry, tok_entry);
token_destroy(tok);
}
bool lex_tokens_available(struct lex *lex)
{
if (!b_queue_empty(&lex->lex_queue)) {
return true;
}
if (line_source_input_available(lex->lex_source)) {
return true;
}
return false;
}

52
toolchain/ifc/lex.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef IFC_LEX_H_
#define IFC_LEX_H_
#include "status.h"
#include "token.h"
#include <blue/core/queue.h>
#include <blue/ds/dict.h>
#include <blue/ds/string.h>
#include <stdint.h>
struct lex {
struct lex_symbol_node *lex_sym_tree;
struct line_source *lex_source;
enum status lex_status;
b_queue lex_queue;
b_string *lex_temp;
b_queue lex_state;
unsigned int lex_brace_depth;
struct file_cell lex_token_start, lex_token_end;
};
struct lex_symbol_node {
char s_char;
struct lex_token_def *s_def;
b_queue_entry s_entry;
b_queue s_children;
};
struct lex_token_def {
int id;
const char *name;
uint64_t name_hash;
};
struct token;
struct line_source;
extern struct lex *lex_create(struct line_source *src);
extern void lex_destroy(struct lex *lex);
extern enum status lex_get_status(const struct lex *lex);
extern struct line_source *lex_get_line_source(const struct lex *lex);
extern const struct file_cell *lex_get_cursor(const struct lex *lex);
extern struct token *lex_peek(struct lex *lex);
extern void lex_advance(struct lex *lex);
#endif

164
toolchain/ifc/line-source.c Normal file
View File

@@ -0,0 +1,164 @@
#include "line-source.h"
enum status line_source_init(
struct line_source *src,
const char *path,
b_stream *stream)
{
memset(src, 0x0, sizeof *src);
src->s_lines = b_array_create();
if (!src->s_lines) {
return ERR_NO_MEMORY;
}
src->s_stream = stream;
src->s_path = path;
src->s_cursor.c_col = 1;
src->s_cursor.c_row = 1;
return SUCCESS;
}
void line_source_cleanup(struct line_source *src)
{
if (src->s_linebuf_ptr) {
b_iterator_unref(src->s_linebuf_ptr);
}
if (src->s_lines) {
b_array_unref(src->s_lines);
}
memset(src, 0x0, sizeof *src);
}
const char *line_source_get_path(const struct line_source *src)
{
return src->s_path;
}
const struct file_cell *line_source_get_cursor(const struct line_source *src)
{
return &src->s_cursor;
}
static enum status refill_linebuf(struct line_source *src)
{
if (!src->s_stream) {
return ERR_EOF;
}
if (src->s_linebuf_ptr) {
b_iterator_unref(src->s_linebuf_ptr);
src->s_linebuf_ptr = NULL;
}
b_stringstream *s = b_stringstream_create();
b_status status = b_stream_read_line_s(src->s_stream, s);
if (status == B_ERR_NO_DATA) {
return ERR_EOF;
}
if (!B_OK(status)) {
return ERR_INTERNAL_FAILURE;
}
b_string *line = b_string_create();
b_string_replace_all_with_stringstream(line, s);
b_stringstream_unref(s);
b_array_append(src->s_lines, line);
b_string_unref(line);
src->s_linebuf = line;
src->s_linebuf_ptr = b_iterator_begin(src->s_linebuf);
return SUCCESS;
}
static int peek(struct line_source *src)
{
enum status status = SUCCESS;
if (!src->s_linebuf_ptr || !b_iterator_is_valid(src->s_linebuf_ptr)) {
status = refill_linebuf(src);
}
if (status != SUCCESS) {
return -status;
}
if (b_string_get_size(src->s_linebuf, B_STRLEN_NORMAL) == 0) {
return -ERR_EOF;
}
b_wchar c = b_iterator_get_value(src->s_linebuf_ptr).v_int;
return c;
}
static int advance(struct line_source *src)
{
enum status status = SUCCESS;
if (!b_iterator_is_valid(src->s_linebuf_ptr)) {
status = refill_linebuf(src);
}
if (status != SUCCESS) {
return -status;
}
if (b_string_get_size(src->s_linebuf, B_STRLEN_NORMAL) == 0) {
return -ERR_EOF;
}
b_wchar c = b_iterator_get_value(src->s_linebuf_ptr).v_int;
b_iterator_move_next(src->s_linebuf_ptr);
src->s_cursor.c_col++;
if (c == '\n') {
src->s_cursor.c_col = 1;
src->s_cursor.c_row++;
}
return c;
}
b_wchar line_source_peekc(struct line_source *src)
{
return peek(src);
}
b_wchar line_source_getc(struct line_source *src)
{
return advance(src);
}
enum status line_source_get_row(
struct line_source *src,
size_t row,
const b_string **out)
{
if (row == 0) {
return ERR_INVALID_ARGUMENT;
}
row--;
if (row >= b_array_size(src->s_lines)) {
return ERR_EOF;
}
b_string *line = b_array_at(src->s_lines, row);
*out = line;
return SUCCESS;
}
bool line_source_input_available(struct line_source *src)
{
return src->s_linebuf_ptr && b_iterator_is_valid(src->s_linebuf_ptr);
}

View File

@@ -0,0 +1,39 @@
#ifndef LINE_SOURCE_H_
#define LINE_SOURCE_H_
#include "file-span.h"
#include "status.h"
#include <blue/core/stream.h>
#include <blue/ds/array.h>
#include <blue/ds/string.h>
struct line_source {
b_stream *s_stream;
const char *s_path;
b_string *s_linebuf;
b_iterator *s_linebuf_ptr;
b_array *s_lines;
struct file_cell s_cursor;
};
extern enum status line_source_init(
struct line_source *src,
const char *path,
b_stream *stream);
extern void line_source_cleanup(struct line_source *src);
extern const char *line_source_get_path(const struct line_source *src);
extern const struct file_cell *line_source_get_cursor(
const struct line_source *src);
extern b_wchar line_source_peekc(struct line_source *src);
extern b_wchar line_source_getc(struct line_source *src);
extern enum status line_source_get_row(
struct line_source *src,
size_t row,
const b_string **out);
extern bool line_source_input_available(struct line_source *src);
#endif

166
toolchain/ifc/main.c Normal file
View File

@@ -0,0 +1,166 @@
#include "backend.h"
#include "ctx.h"
#include "interface.h"
#include "lex.h"
#include "line-source.h"
#include "msg.h"
#include "parse.h"
#include <blue/cmd.h>
#include <blue/io/file.h>
#include <blue/io/path.h>
#define CMD_ID 0
enum {
ARG_SRCPATH,
OPT_BACKEND,
OPT_BACKEND_ARG_NAME,
};
int main(int argc, const char **argv)
{
return b_command_dispatch(CMD_ID, argc, argv);
}
static void print_msg(struct msg_definition *msg)
{
printf(" msg: %s\n", msg->msg_name);
b_queue_entry *entry = b_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
printf(" param:");
type_print(param->p_type);
printf(" %s\n", param->p_name);
entry = b_queue_next(entry);
}
entry = b_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
printf(" result:");
type_print(param->p_type);
printf(" %s\n", param->p_name);
entry = b_queue_next(entry);
}
}
static void print_interface(struct interface_definition *iface)
{
printf("interface: %s\n", iface->if_name);
b_queue_entry *entry = b_queue_first(&iface->if_msg);
while (entry) {
struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
print_msg(msg);
entry = b_queue_next(entry);
}
}
static int ifc(const b_command *self, const b_arglist *opt, const b_array *args)
{
const char *path = NULL;
b_arglist_get_string(opt, B_COMMAND_INVALID_ID, ARG_SRCPATH, 0, &path);
if (!path) {
b_arglist_report_missing_args(
opt,
B_COMMAND_INVALID_ID,
ARG_SRCPATH,
0);
return -1;
}
b_file *file = NULL;
b_result result
= b_file_open(NULL, B_RV_PATH(path), B_FILE_READ_ONLY, &file);
if (b_result_is_error(result)) {
b_throw(result);
return -1;
}
struct line_source src;
line_source_init(&src, path, file);
struct ctx *ctx = ctx_create();
struct lex *lex = lex_create(&src);
#if 0
struct token *tok = lex_peek(lex);
while (tok) {
printf("%s", token_type_to_string(tok->tok_type));
switch (tok->tok_value_type) {
case TOK_V_INT:
printf(" %lld", tok->tok_int);
break;
case TOK_V_STRING:
printf(" %s", tok->tok_str);
break;
case TOK_V_SYMBOL:
printf(" %s", token_symbol_to_string(tok->tok_sym));
break;
case TOK_V_KEYWORD:
printf(" %s", token_keyword_to_string(tok->tok_kw));
break;
default:
break;
}
printf("\n");
lex_advance(lex);
tok = lex_peek(lex);
}
#endif
struct interface_definition *iface
= parse_interface_definition(ctx, lex);
if (!iface) {
return -1;
}
const struct backend *backend = c_mpc_backend();
int err = backend->b_emit(iface);
return err;
}
B_COMMAND(CMD_ID, B_COMMAND_INVALID_ID)
{
B_COMMAND_NAME("ifc");
B_COMMAND_DESC("interface definition compiler.");
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
B_COMMAND_FUNCTION(ifc);
B_COMMAND_HELP_OPTION();
B_COMMAND_ARG(ARG_SRCPATH)
{
B_ARG_NAME("source-file");
B_ARG_DESC("the interface file to compile.");
B_ARG_NR_VALUES(1);
}
B_COMMAND_OPTION(OPT_BACKEND)
{
B_OPTION_LONG_NAME("backend");
B_OPTION_SHORT_NAME('b');
B_OPTION_DESC("which backend to use.");
B_OPTION_ARG(OPT_BACKEND_ARG_NAME)
{
B_ARG_NAME("backend-name");
B_ARG_NR_VALUES(1);
B_ARG_ALLOWED_VALUES("c-mpc");
}
}
B_COMMAND_USAGE()
{
B_COMMAND_USAGE_ARG(ARG_SRCPATH);
B_COMMAND_USAGE_OPT(OPT_BACKEND);
}
}

113
toolchain/ifc/msg.c Normal file
View File

@@ -0,0 +1,113 @@
#include "msg.h"
#include <blue/ds/string.h>
#include <stdlib.h>
#include <string.h>
struct msg_definition *msg_definition_create(const char *name)
{
struct msg_definition *out = malloc(sizeof *out);
if (!out) {
return NULL;
}
memset(out, 0x0, sizeof *out);
out->msg_name = b_strdup(name);
return out;
}
void msg_definition_destroy(struct msg_definition *msg)
{
b_queue_entry *entry = b_queue_pop_front(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
free(param->p_name);
free(param);
entry = b_queue_pop_front(&msg->msg_params);
}
entry = b_queue_pop_front(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
free(param->p_name);
free(param);
entry = b_queue_pop_front(&msg->msg_results);
}
free(msg->msg_name);
free(msg);
}
bool msg_definition_has_param(struct msg_definition *msg, const char *name)
{
b_queue_entry *entry = b_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
if (!strcmp(param->p_name, name)) {
return true;
}
entry = b_queue_next(entry);
}
return false;
}
bool msg_definition_has_result(struct msg_definition *msg, const char *name)
{
b_queue_entry *entry = b_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
if (!strcmp(param->p_name, name)) {
return true;
}
entry = b_queue_next(entry);
}
return false;
}
int msg_definition_add_param(
struct msg_definition *msg,
const struct type *type,
const char *name)
{
struct msg_parameter *param = malloc(sizeof *param);
if (!param) {
return -1;
}
memset(param, 0x0, sizeof *param);
param->p_type = type;
param->p_name = b_strdup(name);
b_queue_push_back(&msg->msg_params, &param->p_entry);
return 0;
}
int msg_definition_add_result(
struct msg_definition *msg,
const struct type *type,
const char *name)
{
struct msg_parameter *param = malloc(sizeof *param);
if (!param) {
return -1;
}
memset(param, 0x0, sizeof *param);
param->p_type = type;
param->p_name = b_strdup(name);
b_queue_push_back(&msg->msg_results, &param->p_entry);
return 0;
}

41
toolchain/ifc/msg.h Normal file
View File

@@ -0,0 +1,41 @@
#ifndef IFC_MSG_H_
#define IFC_MSG_H_
#include <blue/core/queue.h>
struct type;
struct msg_parameter {
char *p_name;
const struct type *p_type;
b_queue_entry p_entry;
};
struct msg_definition {
char *msg_name;
b_queue_entry msg_entry;
b_queue msg_params;
b_queue msg_results;
};
extern struct msg_definition *msg_definition_create(const char *name);
extern void msg_definition_destroy(struct msg_definition *msg);
extern bool msg_definition_has_param(
struct msg_definition *msg,
const char *name);
extern bool msg_definition_has_result(
struct msg_definition *msg,
const char *name);
extern int msg_definition_add_param(
struct msg_definition *msg,
const struct type *type,
const char *name);
extern int msg_definition_add_result(
struct msg_definition *msg,
const struct type *type,
const char *name);
#endif

287
toolchain/ifc/parse.c Normal file
View File

@@ -0,0 +1,287 @@
#include "ctx.h"
#include "interface.h"
#include "lex.h"
#include "msg.h"
#include <stdio.h>
#define report_error(...) fprintf(stderr, __VA_ARGS__)
static bool peek_keyword(struct lex *lex, enum token_keyword kw)
{
struct token *tok = lex_peek(lex);
return (tok && tok->tok_type == TOK_KEYWORD && tok->tok_kw == kw);
}
static bool parse_keyword(struct lex *lex, enum token_keyword kw)
{
struct token *tok = lex_peek(lex);
if (!tok || tok->tok_type != TOK_KEYWORD || tok->tok_kw != kw) {
return false;
}
lex_advance(lex);
return true;
}
static bool parse_symbol(struct lex *lex, enum token_symbol sym)
{
struct token *tok = lex_peek(lex);
if (!tok || tok->tok_type != TOK_SYMBOL || tok->tok_sym != sym) {
return false;
}
lex_advance(lex);
return true;
}
static bool parse_word(struct lex *lex, char **out)
{
struct token *tok = lex_peek(lex);
if (!tok || tok->tok_type != TOK_WORD) {
return false;
}
*out = tok->tok_str;
tok->tok_str = NULL;
lex_advance(lex);
return true;
}
struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex)
{
struct msg_definition *msg = NULL;
if (!parse_keyword(lex, KW_MSG)) {
report_error("expected `msg` keyword\n");
goto fail;
}
char *msg_name = NULL;
if (!parse_word(lex, &msg_name)) {
report_error("expected message identifier\n");
goto fail;
}
msg = msg_definition_create(msg_name);
free(msg_name);
if (!parse_symbol(lex, SYM_LEFT_PAREN)) {
report_error("expected `(` after message identifier\n");
goto fail;
}
size_t i = 0;
bool ok = true;
while (ok) {
if (parse_symbol(lex, SYM_RIGHT_PAREN)) {
break;
}
if (i > 0 && !parse_symbol(lex, SYM_COMMA)) {
report_error("expected `,` after message parameter\n");
ok = false;
break;
}
char *type_name;
if (!parse_word(lex, &type_name)) {
report_error("expected message parameter type\n");
ok = false;
break;
}
const struct type *type = ctx_get_type(ctx, type_name);
if (!type) {
report_error(
"message parameter has unknown type "
"'%s'\n",
type_name);
free(type_name);
ok = false;
break;
}
free(type_name);
char *param_name;
if (!parse_word(lex, &param_name)) {
report_error("expected message parameter name\n");
ok = false;
break;
}
bool duplicate = msg_definition_has_param(msg, param_name)
|| msg_definition_has_result(msg, param_name);
if (duplicate) {
free(param_name);
report_error(
"message has multiple parameters/results with "
"name '%s'\n",
param_name);
ok = false;
break;
}
msg_definition_add_param(msg, type, param_name);
free(param_name);
i++;
}
if (!ok) {
goto fail;
}
if (!parse_symbol(lex, SYM_HYPHEN_RIGHT_ANGLE)) {
report_error("expected `->` after message parameter list\n");
goto fail;
}
if (!parse_symbol(lex, SYM_LEFT_PAREN)) {
report_error("expected `(` for message results list\n");
goto fail;
}
i = 0;
while (ok) {
if (parse_symbol(lex, SYM_RIGHT_PAREN)) {
break;
}
if (i > 0 && !parse_symbol(lex, SYM_COMMA)) {
report_error(
"expected `,` or `)` after message result\n");
ok = false;
break;
}
char *type_name;
if (!parse_word(lex, &type_name)) {
report_error("expected message result type\n");
ok = false;
break;
}
const struct type *type = ctx_get_type(ctx, type_name);
if (!type) {
report_error(
"message result has unknown type "
"'%s'\n",
type_name);
free(type_name);
ok = false;
break;
}
free(type_name);
char *result_name;
if (!parse_word(lex, &result_name)) {
report_error("expected message parameter name\n");
ok = false;
break;
}
bool duplicate = msg_definition_has_param(msg, result_name)
|| msg_definition_has_result(msg, result_name);
if (duplicate) {
report_error(
"message has multiple parameters/results with "
"name '%s'\n",
result_name);
free(result_name);
ok = false;
break;
}
msg_definition_add_result(msg, type, result_name);
free(result_name);
}
if (!parse_symbol(lex, SYM_SEMICOLON)) {
report_error("expected `;` after message definition\n");
goto fail;
}
return msg;
fail:
if (msg) {
msg_definition_destroy(msg);
}
return NULL;
}
struct interface_definition *parse_interface_definition(
struct ctx *ctx,
struct lex *lex)
{
struct interface_definition *iface = NULL;
if (!parse_keyword(lex, KW_INTERFACE)) {
report_error("expected `interface` keyword");
goto fail;
}
char *if_name = NULL;
if (!parse_word(lex, &if_name)) {
report_error("expected interface identifier");
goto fail;
}
iface = interface_definition_create(if_name);
free(if_name);
if (!iface) {
goto fail;
}
if (!parse_symbol(lex, SYM_LEFT_BRACE)) {
report_error("expected `{` after interface identifier");
goto fail;
}
bool ok = true;
while (ok) {
if (parse_symbol(lex, SYM_RIGHT_BRACE)) {
break;
}
if (peek_keyword(lex, KW_MSG)) {
struct msg_definition *msg
= parse_msg_definition(ctx, lex);
if (!msg) {
ok = false;
break;
}
if (interface_definition_has_msg(
iface,
msg->msg_name)) {
msg_definition_destroy(msg);
ok = false;
break;
}
interface_definition_add_msg(iface, msg);
continue;
}
report_error("expected `}` or message definition\n");
ok = false;
break;
}
if (!ok) {
goto fail;
}
return iface;
fail:
if (iface) {
interface_definition_destroy(iface);
}
return NULL;
}

12
toolchain/ifc/parse.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef IFC_PARSE_H_
#define IFC_PARSE_H_
struct ctx;
struct lex;
struct interface_definition;
extern struct interface_definition *parse_interface_definition(
struct ctx *ctx,
struct lex *lex);
#endif

20
toolchain/ifc/status.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef IFC_STATUS_H_
#define IFC_STATUS_H_
enum status {
SUCCESS = 0,
ERR_EOF,
ERR_BAD_SYNTAX,
ERR_BAD_FORMAT,
ERR_BAD_STATE,
ERR_INVALID_VALUE,
ERR_INVALID_ARGUMENT,
ERR_NO_MEMORY,
ERR_NO_ENTRY,
ERR_NO_DATA,
ERR_NAME_EXISTS,
ERR_NOT_SUPPORTED,
ERR_INTERNAL_FAILURE,
};
#endif

63
toolchain/ifc/token.c Normal file
View File

@@ -0,0 +1,63 @@
#include "token.h"
void token_destroy(struct token *tok)
{
switch (tok->tok_value_type) {
case TOK_V_STRING:
if (tok->tok_str) {
free(tok->tok_str);
}
break;
default:
break;
}
free(tok);
}
#define ENUM_STR(x) \
case x: \
return #x
const char *token_type_to_string(enum token_type type)
{
switch (type) {
ENUM_STR(TOK_NONE);
ENUM_STR(TOK_INT);
ENUM_STR(TOK_SYMBOL);
ENUM_STR(TOK_WORD);
ENUM_STR(TOK_NAME);
ENUM_STR(TOK_STRING);
ENUM_STR(TOK_KEYWORD);
default:
return "";
}
}
const char *token_symbol_to_string(enum token_symbol sym)
{
switch (sym) {
ENUM_STR(SYM_NONE);
ENUM_STR(SYM_COMMA);
ENUM_STR(SYM_SEMICOLON);
ENUM_STR(SYM_HYPHEN);
ENUM_STR(SYM_LEFT_BRACE);
ENUM_STR(SYM_RIGHT_BRACE);
ENUM_STR(SYM_LEFT_PAREN);
ENUM_STR(SYM_RIGHT_PAREN);
ENUM_STR(SYM_HYPHEN_RIGHT_ANGLE);
default:
return "";
}
}
const char *token_keyword_to_string(enum token_keyword kw)
{
switch (kw) {
ENUM_STR(KW_NONE);
ENUM_STR(KW_INTERFACE);
ENUM_STR(KW_MSG);
default:
return "";
}
}

70
toolchain/ifc/token.h Normal file
View File

@@ -0,0 +1,70 @@
#ifndef IFC_TOKEN_H_
#define IFC_TOKEN_H_
#include "file-span.h"
#include <blue/core/queue.h>
#define TOKEN_TYPE(tok) ((tok) ? (tok)->tok_type : TOK_NONE)
#define TOKEN_IS(tok, type) ((tok) && ((tok)->tok_type & (type)) != 0)
#define TOKEN_IS_SYMBOL(tok, sym) \
((tok) && (tok)->tok_type == TOK_SYMBOL && (tok)->tok_sym == (sym))
enum token_type {
TOK_NONE = 0,
TOK_SYMBOL = 0x0001u,
TOK_KEYWORD = 0x0002u,
TOK_WORD = 0x0004u,
TOK_NAME = 0x0008u,
TOK_INT = 0x0010u,
TOK_STRING = 0x0020u,
__TOK_UBOUND = 0x0040u,
};
enum token_value_type {
TOK_V_NONE = 0,
TOK_V_INT,
TOK_V_STRING,
TOK_V_SYMBOL,
TOK_V_KEYWORD,
};
enum token_symbol {
SYM_NONE = 0,
SYM_COMMA = __TOK_UBOUND,
SYM_HYPHEN,
SYM_SEMICOLON,
SYM_LEFT_BRACE,
SYM_RIGHT_BRACE,
SYM_LEFT_PAREN,
SYM_RIGHT_PAREN,
SYM_HYPHEN_RIGHT_ANGLE,
__SYM_UBOUND,
};
enum token_keyword {
KW_NONE = 0,
KW_INTERFACE = __SYM_UBOUND,
KW_MSG,
};
struct token {
struct file_span tok_location;
enum token_type tok_type;
enum token_value_type tok_value_type;
b_queue_entry tok_entry;
union {
char *tok_str;
enum token_symbol tok_sym;
enum token_keyword tok_kw;
long long tok_int;
};
};
extern void token_destroy(struct token *tok);
extern const char *token_type_to_string(enum token_type type);
extern const char *token_symbol_to_string(enum token_symbol sym);
extern const char *token_keyword_to_string(enum token_keyword kw);
#endif

17
toolchain/ifc/type.c Normal file
View File

@@ -0,0 +1,17 @@
#include "type.h"
#include <stdio.h>
void type_print(const struct type *ty)
{
switch (ty->ty_id) {
case TYPE_INT:
printf("int");
break;
case TYPE_STRING:
printf("string");
break;
default:
break;
}
}

17
toolchain/ifc/type.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef IFC_TYPE_H_
#define IFC_TYPE_H_
enum type_id {
TYPE_NONE,
TYPE_INT,
TYPE_STRING,
TYPE_OTHER,
};
struct type {
enum type_id ty_id;
};
extern void type_print(const struct type *ty);
#endif

24
util/merge-compiledb.py Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env python3
import sys
import json
if len(sys.argv) < 3:
print('USAGE: {} <dest-file> [src-files...]'.format(sys.argv[0]))
exit(-1)
dest_path = sys.argv[1]
src_paths = sys.argv[2:]
dest = open(dest_path, 'r')
dest_data = json.load(dest)
dest.close()
for src_path in src_paths:
src = open(src_path, 'r')
src_data = json.load(src)
dest_data += src_data
src.close()
dest = open(dest_path, 'w')
json.dump(dest_data, dest, indent=4)
dest.close()

0
util/sysroot-tool.py Normal file → Executable file
View File