52#ifndef COMPILER_LINE_FRONTEND_H
53#define COMPILER_LINE_FRONTEND_H
163 while (begin < text.size()
and std::isspace(
static_cast<unsigned char>(text[begin])))
166 size_t end = text.size();
167 while (end > begin
and std::isspace(
static_cast<unsigned char>(text[end - 1])))
170 return std::string(text.substr(begin, end - begin));
175 if (text.size() >= 2
and text.front() ==
'"' and text.back() ==
'"')
176 return std::string(text.substr(1, text.size() - 2));
177 return std::string(text);
183 std::istringstream
in{std::string(text)};
195 const char *
const begin = text.data();
196 const char *
const finish = begin + text.size();
197 const auto result = std::from_chars(begin, finish,
value);
198 return result.ec == std::errc{}
and result.ptr == finish;
203 return std::isalpha(
ch)
or ch ==
'_';
208 return std::isalnum(
ch)
or ch ==
'_';
216 for (
size_t i = 1; i < text.size(); ++i)
256 return static_cast<size_t>(-1);
264 out.text = std::string(text);
274 out.text = std::string(text);
275 out.integer_value = 0;
284 if (tokens.
size() != 2)
352 parsed.functions.append(std::move(def));
364 "expected 'let <name> = int <value>' or 'let <name> = call <func> <a> <b>'");
380 if (tokens.
access(3) ==
"int")
382 if (tokens.
size() != 5)
397 parsed.lets.append(std::move(def));
401 if (tokens.
access(3) ==
"call")
403 if (tokens.
size() != 7)
429 parsed.lets.append(std::move(def));
450 if (
const auto comment = line.find(
'#'); comment != std::string_view::npos)
451 line = line.substr(0, comment);
458 if (
not tokens.is_empty())
460 if (tokens.access(0) ==
"import")
462 else if (tokens.access(0) ==
"func")
464 else if (tokens.access(0) ==
"let")
469 "unknown line-frontend declaration '" + tokens.access(0) +
"'");
473 if (
newline == std::string::npos)
489 for (
size_t j = 0; j <
parsed.functions.size(); ++j)
491 for (
size_t j = 0; j <
parsed.lets.size(); ++j)
507 for (
size_t i = 0; i < result.issues.size(); ++i)
509 const auto &
issue = result.issues.access(i);
513 "cannot resolve line-frontend import '" +
issue.dependency_name +
"'");
517 "cyclic line-frontend import involving '" +
issue.module_name +
"' and '"
518 +
issue.dependency_name +
"'");
521 for (
size_t i = 0; i < result.order.size(); ++i)
533 std::ostringstream
out;
534 out <<
"LineProgram\n";
535 for (
size_t i = 0; i <
functions_.size(); ++i)
538 out <<
" func " <<
fn.name <<
" " <<
fn.left_param <<
" " <<
fn.right_param <<
" = "
541 for (
size_t i = 0; i <
lets_.size(); ++i)
544 out <<
" let " <<
let.name <<
" = ";
546 out <<
"int " <<
let.integer_value;
548 out <<
"call " <<
let.callee <<
" " <<
let.arg1.text <<
" " <<
let.arg2.text;
556 std::ostringstream
out;
559 out <<
" TopLevelLets: " <<
lets_.size() <<
'\n';
566 for (
size_t i = 0; i <
lets_.size(); ++i)
575 lets_.access(i).callee_module_name =
value->provider_module_name;
589 lets_.access(i).callee_module_name =
resolution.binding.provider_module_name;
605 const auto *symbol_id = bindings.
lookup(operand.
text);
606 if (symbol_id !=
nullptr)
611 "unknown function-local name '" + operand.
text +
"' in '" + function.
name +
"'");
622 "top-level line frontend currently accepts only integer call arguments");
642 return builder.emit_constant(function,
714 append_error(
"line frontend: no input sources were provided");
718 for (
size_t i = 0; i <
inputs.size(); ++i)
759 for (
size_t j = 0; j <
parsed.imports.size(); ++j)
765 for (
size_t j = 0; j <
parsed.functions.size(); ++j)
767 parsed.functions.access(j).name,
768 parsed.functions.access(j).name_span});
769 for (
size_t j = 0; j <
parsed.lets.size(); ++j)
771 parsed.lets.access(j).name,
772 parsed.lets.access(j).name_span});
778 (
void) resolve_import_order();
780 for (
size_t i = 0; i < parsed_sources_.
size(); ++i)
783 flatten_program_in_import_order();
784 record_import_order_artifact();
786 record_text_artifact(
"line.parse", dump_parsed_program());
799 for (
size_t i = 0; i < parsed_sources_.
size(); ++i)
801 const auto &
module = parsed_sources_.access(i);
805 for (
size_t j = 0; j <
module.functions.size(); ++j)
807 const auto &
fn =
module.functions.access(j);
808 const auto result = locals.
declare(Compiler_Symbol_Kind::Function,
fn.name,
fn.name_span);
809 if (result.duplicate_local())
810 emit_error(
fn.name_span,
812 "duplicate line-frontend function '" +
fn.name +
"'");
815 for (
size_t j = 0; j <
module.lets.size(); ++j)
817 const auto &
let =
module.lets.access(j);
818 const auto result = locals.
declare(Compiler_Symbol_Kind::Global,
let.name,
let.name_span);
819 if (result.duplicate_local())
822 if (
existing.kind == Compiler_Symbol_Kind::Function)
823 emit_error(
let.name_span,
825 "top-level let '" +
let.name +
"' conflicts with a function name");
827 emit_error(
let.name_span,
829 "duplicate line-frontend top-level let '" +
let.name +
"'");
839 (
void) validate_top_level_calls(table,
env);
841 for (
size_t i = 0; i < functions_.
size(); ++i)
843 const auto &
fn = functions_.
access(i);
846 (
void) locals.
declare(Compiler_Symbol_Kind::Parameter,
fn.left_param,
fn.span);
847 (
void) locals.
declare(Compiler_Symbol_Kind::Parameter,
fn.right_param,
fn.span);
848 (
void) validate_operand_in_function(
fn.lhs,
fn, locals);
849 (
void) validate_operand_in_function(
fn.rhs,
fn, locals);
852 record_text_artifact(
"line.sema", dump_semantic_state());
866 hir_module_ =
builder.make_module();
867 const auto function_type
870 for (
size_t i = 0; i < functions_.
size(); ++i)
872 const auto &
fn = functions_.
access(i);
873 auto *body =
builder.make_block();
874 auto *function =
builder.make_function(
fn.name, function_type,
fn.name_span, body,
fn.span);
883 builder.append_function(*hir_module_, function);
886 for (
size_t i = 0; i < lets_.
size(); ++i)
889 if (
let.kind == Let_Definition::Kind::Integer)
890 builder.append_top_level_statement(
906 builder.append_top_level_statement(
913 return hir_module_ !=
nullptr;
926 ir_module_ =
builder.make_module();
927 if (ir_module_ ==
nullptr)
929 append_error(
"ir: null IR module produced by line frontend");
933 const auto function_type
936 for (
size_t i = 0; i < lets_.
size(); ++i)
937 (
void)
builder.add_global_slot(*ir_module_,
943 for (
size_t i = 0; i < functions_.
size(); ++i)
945 const auto &
fn = functions_.
access(i);
946 auto *function =
builder.make_function(
fn.name, function_type,
fn.span);
947 const auto id =
builder.append_function(*ir_module_, function);
948 function_ids.
append({
fn.module_name +
"::" +
fn.name,
id});
955 for (
size_t i = 0; i < function_ids.
size(); ++i)
956 if (function_ids.
access(i).first == key)
957 return function_ids.
access(i).second;
961 for (
size_t i = 0; i < functions_.
size(); ++i)
963 auto &function = *ir_module_->
functions.access(i);
966 Compiler_IR_Slot_Kind::Parameter,
971 Compiler_IR_Slot_Kind::Parameter,
975 const auto entry =
builder.create_block(function,
"entry");
976 const auto exit =
builder.create_block(function,
"exit");
977 builder.set_entry_block(function, entry);
980 const auto lhs = build_ir_operand(
982 const auto rhs = build_ir_operand(
984 const auto result =
builder.emit_binary(
992 auto *top =
builder.make_function(
"<top-level>");
993 builder.set_top_level(*ir_module_, top);
994 const auto entry =
builder.create_block(*top,
"entry");
995 const auto exit =
builder.create_block(*top,
"exit");
996 builder.set_entry_block(*top, entry);
999 for (
size_t i = 0; i < lets_.
size(); ++i)
1002 if (
let.kind == Let_Definition::Kind::Integer)
1014 std::to_string(
let.arg1.integer_value),
1019 std::to_string(
let.arg2.integer_value),
1021 const auto callee =
builder.emit_function_ref(
1022 *top, entry, find_function_id(
let.callee_module_name,
let.callee), function_type,
let.span);
1045 return &diagnostics_;
1055 return &diagnostics_;
1095 return module_descriptors_;
1105 return merge_order_;
1115 return module_metadata_;
1137 for (
size_t i = artifacts_.
size(); i > 0; --i)
1138 if (artifacts_.
access(i - 1).label == label)
1139 return &artifacts_.
access(i - 1);
Reusable interface for language frontends that plug into common drivers.
Reusable builder helpers for constructing HIR directly.
Reusable builder helpers for constructing explicit IR directly.
Reusable diagnostics for top-level inter-module name resolution.
Reusable top-level name lookup over bound module surfaces.
Reusable source-name module dependency resolution helpers.
Reusable namespace-separated semantic environment for modules.
Reusable lexical bindings and symbol records for frontends.
size_t size_t int32_t value
size_t size_t int32_t * out
Abstract language frontend that can feed reusable drivers.
Small reusable helper that allocates and connects HIR nodes.
Arena-backed ownership context for HIR nodes.
void reset() noexcept
Destroys all tracked objects and rewinds the arena.
Small reusable helper that allocates and connects IR nodes.
Arena-backed ownership context for IR nodes.
void reset() noexcept
Destroys all tracked objects and rewinds the arena.
Small example frontend for a line-oriented language.
bool validate_top_level_calls(const Compiler_Module_Name_Table &table, const Compiler_Module_Semantic_Environment &env)
DynArray< std::string > source_names_
static bool parse_operand(std::string_view text, const Source_Span &span, Operand &out)
static Compiler_Operator_Kind parse_operator_name(std::string_view text) noexcept
const DynArray< size_t > & module_merge_order() const noexcept override
Returns the dependency-resolved merge order from the last parse().
const Compiler_IR_Module * ir_module() const noexcept override
Returns the IR module produced by the last lower_ir() call.
DynArray< Parsed_Source > parsed_sources_
Compiler_HIR_Context hir_ctx_
bool parse() override
Parses all registered sources, builds module descriptors and metadata, resolves import order,...
DynArray< Compiler_Driver_Artifact > artifacts_
bool parse_let_line(Parsed_Source &parsed, const DynArray< std::string > &tokens, const Source_Span &line_span)
bool analyze() override
Performs semantic validation: duplicate declarations, module linking, name binding,...
DynArray< size_t > merge_order_
const Compiler_Type_Context * type_context() const noexcept override
Returns the shared type context used by the line frontend.
Diagnostic_Engine * diagnostic_engine() noexcept override
Returns the mutable diagnostic engine for this frontend.
const Compiler_HIR_Module * hir_module() const noexcept override
Returns the HIR module produced by the last lower_hir() call.
Compiler_IR_Value_Id build_ir_operand(Compiler_IR_Builder &builder, Compiler_IR_Function &function, const Compiler_IR_Block_Id block_id, const Operand &operand, const Compiler_IR_Local_Slot_Id left_slot, const Compiler_IR_Local_Slot_Id right_slot, const Function_Definition &definition) const
static std::string trim_copy(std::string_view text)
bool parse_function_line(Parsed_Source &parsed, const DynArray< std::string > &tokens, const Source_Span &line_span)
void record_import_order_artifact()
const DynArray< std::string > & errors() const noexcept override
Returns hard frontend-level errors collected outside the diagnostic engine.
DynArray< Function_Definition > functions_
DynArray< Compiler_Module_Descriptor > module_descriptors_
size_t find_source_index(std::string_view name) const noexcept
std::string dump_parsed_program() const
bool validate_operand_in_function(const Operand &operand, const Function_Definition &function, const Compiler_Symbol_Bindings &bindings)
const DynArray< Compiler_Driver_Artifact > & artifacts() const noexcept override
Returns all frontend-produced artifacts from the last run.
void record_text_artifact(const std::string &label, std::string text)
bool parse_import_line(Parsed_Source &parsed, const DynArray< std::string > &tokens, const Source_Span &line_span)
DynArray< std::string > errors_
DynArray< Source_File_Id > source_ids_
void flatten_program_in_import_order()
static std::string trim_quotes_copy(std::string_view text)
static bool is_identifier_continue(const unsigned char ch) noexcept
bool lower_ir() override
Lowers the analyzed line program into a reusable flat IR module.
const DynArray< Compiler_Module_Metadata > & module_metadata() const noexcept override
Returns the module metadata built during parse().
Compiler_IR_Module * ir_module_
const DynArray< std::string > & warnings() const noexcept override
Returns non-fatal frontend-level warnings.
Compiler_HIR_Expr * build_hir_operand(Compiler_HIR_Builder &builder, const Operand &operand) const
Compiler_Line_Frontend(const size_t arena_size=1<< 20)
Constructs a line-oriented frontend with reusable HIR/IR arena storage.
void append_error(const std::string &text)
Diagnostic_Engine diagnostics_
DynArray< std::string > warnings_
static bool is_identifier_start(const unsigned char ch) noexcept
DynArray< Compiler_Module_Metadata > module_metadata_
bool parse_source_file(Parsed_Source &parsed)
static bool parse_identifier(std::string_view text) noexcept
bool validate_top_level_operand(const Operand &operand, const Source_Span &span)
DynArray< Let_Definition > lets_
static DynArray< std::string > split_tokens(std::string_view text)
Compiler_HIR_Module * hir_module_
void clear() noexcept override
Resets all frontend-owned state so the instance can be reused.
bool resolve_import_order()
bool load_sources(const DynArray< Compiler_Driver_Source > &inputs) override
Registers ordered in-memory sources for the next compilation run.
void emit_error(const Source_Span &span, const std::string &code, const std::string &message)
const DynArray< Compiler_Module_Descriptor > & module_descriptors() const noexcept override
Returns the module descriptors built during parse().
bool lower_hir() override
Lowers the analyzed line program into a reusable HIR module.
static bool parse_integer(std::string_view text, long long &value) noexcept
const Diagnostic_Engine * diagnostic_engine() const noexcept override
Returns the read-only diagnostic engine for this frontend.
Compiler_Type_Context types_
const Compiler_Driver_Artifact * find_artifact(std::string_view label) const noexcept override
Finds one frontend artifact by exact label (last-write wins).
Compiler_IR_Context ir_ctx_
std::string dump_semantic_state() const
const char * name() const noexcept override
Returns the stable frontend name.
Reusable lexical symbol table with stable ids and scope tracking.
Compiler_Symbol_Declare_Result declare(const Compiler_Symbol_Kind kind, const std::string &name, const Source_Span &span)
Declares one symbol in the current scope.
const Compiler_Symbol & symbol(const Compiler_Symbol_Id id) const
Returns one symbol by its stable 1-based identifier.
const Compiler_Symbol_Id * lookup(const std::string &name) const noexcept
Looks up one visible symbol id by name.
size_t enter_scope()
Enters one nested lexical scope.
Context owning all compiler type nodes.
Compiler_Type_Id make_function_type(const DynArray< Compiler_Type_Id > ¶meters, const Compiler_Type_Id result)
Creates a function type.
void clear() noexcept
Drops user-created types and keeps the built-ins.
Compiler_Type_Id integer_type() const noexcept
Returns the preloaded Int type id.
Diagnostic_Builder & code(const std::string &value)
Sets the stable diagnostic code.
size_t emit() const noexcept
Finalizes the builder and returns the diagnostic index.
Diagnostic accumulator and renderer.
void clear() noexcept
Removes all accumulated diagnostics and resets counters.
bool has_errors() const noexcept
Returns whether any error or fatal diagnostic was emitted.
Diagnostic_Builder error(const Source_Span &span, const std::string &msg)
Starts an error diagnostic.
void clear() noexcept
Empties the container.
size_t size() const noexcept
Return the current dimension of array.
T & access(const size_t i) const noexcept
Fast access without checking allocation and bound_min_clock checking.
T & append()
Allocate a new entry to the end of array.
bool is_empty() const noexcept
Return true if the array is empty.
Stores source files and resolves offsets into human-readable data.
const std::string & file_text(const Source_File_Id id) const
Returns the full text of file id.
Source_File_Id add_virtual_file(const std::string &name, const std::string &text)
Registers an in-memory source file.
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
bool merge_report(const std::string &stage, const Report &report, DynArray< std::string > &errors, DynArray< std::string > &warnings)
void append_artifact(DynArray< Compiler_Driver_Artifact > &artifacts, const std::string &label, std::string text)
Main namespace for Aleph-w library functions.
Compiler_Module_Semantic_Environment compiler_build_module_semantic_environment(const Compiler_Module_Name_Table &table)
Builds one namespace-separated semantic environment from a name table.
void message(const char *file, int line, const char *format,...)
Print an informational message with file and line info.
std::string compiler_dump_ir_module(const Compiler_IR_Module *module, const Compiler_Type_Context *types=nullptr)
Dumps all lowered IR in one module deterministically.
const char * compiler_operator_name(const Compiler_Operator_Kind kind) noexcept
Returns a stable debug name for one operator kind.
Compiler_IR_Validation_Report validate_ir_module(const Compiler_IR_Module &module)
Validates all functions in one lowered IR module.
void exit(const char *file, int line, const char *format,...)
Print a message and exit the program.
and
Check uniqueness with explicit hash + equality functors.
std::string compiler_render_module_order(const DynArray< size_t > &order, const DynArray< Compiler_Module_Descriptor > &modules)
Renders one deterministic text artifact for a module order.
Compiler_Module_Resolution_Result compiler_resolve_module_order(const DynArray< Compiler_Module_Descriptor > &modules)
Resolves one dependency-first order for exact-name module imports.
Compiler_Module_Name_Table compiler_build_module_name_table(const Compiler_Module_Binding_Result &bindings)
Builds one reusable per-module name table from bindings.
std::string code(Node *root)
Compute a string with the Lukasiewicz`s word of a tree.
size_t compiler_emit_module_name_resolution_diagnostic(Diagnostic_Engine &diagnostics, const Source_Span &span, const Compiler_Module_Name_Resolution &resolution, const std::string &code, const std::string &subject)
Emits one structured diagnostic for a module-name resolution failure.
size_t Compiler_IR_Value_Id
constexpr size_t compiler_ir_invalid_id() noexcept
Returns the sentinel invalid IR id.
std::string compiler_dump_hir_module(const Compiler_HIR_Module *module, const Compiler_Type_Context &types)
Dumps one HIR module in a deterministic text format.
const Compiler_Module_Bound_Name * compiler_lookup_module_value(const Compiler_Module_Semantic_Environment &env, const std::string_view module_name, const std::string_view symbol_name) noexcept
Looks up one visible value-namespace binding in a module environment.
size_t Compiler_IR_Block_Id
Compiler_Module_Name_Resolution compiler_resolve_module_name(const Compiler_Module_Binding_Result &bindings, const std::string_view module_name, const std::string_view symbol_name, const Compiler_Module_Name_Filter filter=Compiler_Module_Name_Filter::Any)
Resolves one top-level name through reusable per-module bindings.
Compiler_Module_Link_Result compiler_link_module_surfaces(const DynArray< Compiler_Module_Descriptor > &descriptors, const DynArray< Compiler_Module_Metadata > &metadata, const DynArray< size_t > &order)
Links direct-import module surfaces into visible top-level views.
Compiler_Module_Binding_Result compiler_bind_module_surfaces(const Compiler_Module_Link_Result &linkage)
Binds linked module surfaces into one deterministic name view.
Compiler_Operator_Kind
Stable operator kinds shared by reusable compiler layers.
size_t Compiler_IR_Local_Slot_Id
Stable text artifact produced during one pipeline run.
Base class for HIR expressions.
Lowered IR for one function or top-level body.
Lowered IR module with shared global slots and functions.
DynArray< Compiler_IR_Function * > functions
Lowered non-top-level functions.
Compiler_Operator_Kind op
std::string callee_module_name
Resolved declaring module of callee (populated during analysis).
DynArray< Function_Definition > functions
DynArray< Compiler_Module_Dependency > imports
DynArray< Let_Definition > lets
One module descriptor consumed by the reusable resolver.
std::string name
Stable module/source name.
Cached top-level name table over all visible modules.
Semantic environments for all modules in one compilation unit set.
Half-open byte range inside a source file.
Source_File_Id file_id
Stable file identifier; 0 means invalid.