58#ifndef COMPILER_TYPED_SEMA_H
59#define COMPILER_TYPED_SEMA_H
168 const std::string &
code,
170 const std::string ¬e =
"",
171 const std::string &help =
"")
const
177 if (
not note.empty())
179 if (
not help.empty())
199 for (
size_t i =
expr_types.size(); i > 0; --i)
211 if (function ==
nullptr)
229 for (
size_t i =
let_types.size(); i > 0; --i)
230 if (
let_types.access(i - 1).stmt == stmt)
232 let_types.access(i - 1).type_id = type_id;
256 for (
size_t i = 0; i < values.size(); ++i)
257 if (values.access(i) == target)
270 for (
size_t i = 0; i < names.size(); ++i)
271 if (names.access(i) == target)
291 const auto inserted =
scopes.insert(name, binding);
316 for (
size_t i = bindings.size(); i > 0; --i)
317 if (bindings.access(i - 1).name == name)
318 return bindings.access(i - 1).type_id;
324 if (name ==
"Invalid")
330 if (name ==
"Int" or name ==
"Integer")
332 if (name ==
"String")
334 if (name ==
"Char" or name ==
"Character")
353 emit_error(span,
"TYP010",
"cyclic type alias involving '" + binding.
name +
"'");
371 if (binding ==
nullptr)
374 if (binding->alias_decl !=
nullptr)
377 binding->resolved =
true;
378 return binding->type_id;
384 const std::string &what,
385 const std::string &owner)
389 emit_error(span,
"TYP011",
"duplicate " + what +
" '" +
candidate +
"' in '" + owner +
"'");
397 if (module ==
nullptr)
400 for (
size_t i = 0; i <
module->type_declarations.size(); ++i)
402 const auto *
decl =
module->type_declarations.access(i);
410 "duplicate type declaration of '" +
decl->name +
"'");
447 if (binding ==
nullptr or binding->resolved)
464 for (
size_t i = 0; i < node->fields.size(); ++i)
466 const auto &field = node->fields.
access(i);
468 field_names, field.name, field.name_span,
"field", node->name))
477 binding->resolved =
true;
485 for (
size_t i = 0; i < node->variants.size(); ++i)
487 const auto &variant = node->variants.
access(i);
489 variant_names, variant.name, variant.name_span,
"enum variant", node->name))
494 binding->resolved =
true;
502 if (module ==
nullptr)
505 for (
size_t i = 0; i <
module->type_declarations.size(); ++i)
536 emit_error(node->name_span,
"TYP009",
"unknown type name '" + node->name +
"'");
549 for (
size_t i = 0; i < node->members.size(); ++i)
560 for (
size_t i = 0; i < node->parameters.size(); ++i)
575 if (function ==
nullptr)
578 for (
size_t i = 0; i <
type_names.size(); ++i)
580 {function, type_names.access(i).name, type_names.access(i).type_id});
586 if (function ==
nullptr)
610 for (
size_t i = 0; i < quantified_variables.
size(); ++i)
611 if (quantified_variables.
access(i) == resolved)
615 return replacements.
access(j);
629 for (
size_t i = 0; i < type.components.size(); ++i)
638 for (
size_t i = 0; i < type.components.size(); ++i)
685 for (
size_t i = 0; i < type.components.size(); ++i)
690 for (
size_t i = 0; i < type.components.size(); ++i)
731 Compiler_Type_Scheme scheme;
764 if (
const auto *binding =
scopes.lookup(name); binding !=
nullptr)
768 emit_error(span,
"TYP001",
"use of undeclared identifier '" + name +
"'");
775 const std::string &
code,
776 const std::string &
prefix)
793 for (
size_t i = 0; i < function->
parameters.size(); ++i)
816 for (
size_t i = 0; i <
type_names.size(); ++i)
889 +
"' requires an Int operand");
898 "unary operator '!' requires a Bool operand");
935 +
"' requires Int operands");
941 +
"' requires Int operands");
954 +
"' requires Int operands");
960 +
"' requires Int operands");
971 +
"' requires Bool operands");
977 +
"' requires Bool operands");
989 +
"' requires compatible operand types");
1006 for (
size_t i = 0; i < node->arguments.size(); ++i)
1013 for (
size_t i = 0; i < node->arguments.size(); ++i)
1033 if (block ==
nullptr)
1037 for (
size_t i = 0; i < block->statements.size(); ++i)
1047 if (stmt ==
nullptr)
1078 "initializer is incompatible with the declared binding type");
1092 for (
size_t i = 0; i <
type_names.size(); ++i)
1098 binding.
type_id = scheme.type_id;
1099 binding.
polymorphic = scheme.quantified_variables.size() > 0;
1111 const auto value_type
1119 "return expression is incompatible with the inferred function result type");
1138 "if condition must have type Bool");
1152 "while condition must have type Bool");
1165 if (function ==
nullptr)
1176 for (
size_t i = 0; i < function->
parameters.size(); ++i)
1192 "function without explicit returns defaults to Unit");
1199 for (
size_t i = 0; i <
expr_types.size(); ++i)
1203 for (
size_t i = 0; i <
let_types.size(); ++i)
1244 if (module ==
nullptr)
1255 for (
size_t i = 0; i <
module->functions.size(); ++i)
1259 for (
size_t i = 0; i <
module->statements.size(); ++i)
1262 for (
size_t i = 0; i <
module->functions.size(); ++i)
1291 return binding->type_id;
1304 for (
size_t i =
expr_types.size(); i > 0; --i)
1322 for (
size_t i =
let_types.size(); i > 0; --i)
1323 if (
let_types.access(i - 1).stmt == stmt)
1330 const size_t index)
const noexcept
1341 std::ostringstream
out;
1342 out <<
"Typed Semantic Analysis\n";
1350 out <<
" " << entry.name <<
": ";
1351 if (entry.type_id != 0)
1354 out <<
"<unresolved>";
1361 out <<
"Functions\n";
1365 out <<
" " << entry.function->name <<
": " <<
types.
to_string(entry.type_id) <<
'\n';
1371 out <<
"Parameters\n";
1375 out <<
" " << entry.function->name <<
"."
1376 << entry.function->parameters.access(entry.index).name <<
": "
1383 out <<
"Bindings\n";
1384 for (
size_t i = 0; i <
let_types.size(); ++i)
1386 const auto &entry =
let_types.access(i);
1387 out <<
" " << entry.stmt->name <<
": " <<
types.
to_string(entry.type_id) <<
" @"
1388 << entry.stmt->name_span.to_string() <<
'\n';
Name-resolution and basic semantic checks for the compiler-support MVP.
Stable type graph for the compiler-support MVP.
size_t size_t int32_t * out
Name-resolution and basic semantic checker for the MVP AST.
void clear() noexcept
Clears previously collected semantic state.
void analyze_module(const Compiler_Module *module)
Analyzes a parsed module.
Context owning all compiler type nodes.
void set_struct_fields(const Compiler_Type_Id id, const DynArray< std::string > &field_names, const DynArray< Compiler_Type_Id > &field_types) const
Assigns field metadata to a previously created struct type.
bool is_builtin(const Compiler_Type_Id id) const
Returns whether id names a built-in type.
Compiler_Type_Id string_type() const noexcept
Returns the preloaded String type id.
std::string to_string(const Compiler_Type_Id id) const
Renders one type to a deterministic human-readable string.
Compiler_Type_Id make_enum_type(std::string name)
Creates a nominal enum type placeholder.
const Compiler_Type & type(const Compiler_Type_Id id) const
Returns type id.
Compiler_Type_Id invalid_type() const noexcept
Returns the preloaded Invalid type id.
void set_enum_variants(const Compiler_Type_Id id, const DynArray< std::string > &variant_names) const
Assigns variant metadata to a previously created enum type.
Compiler_Type_Id make_type_variable(std::string label="", const bool rigid=false)
Creates a fresh type variable.
Compiler_Type_Id make_tuple_type(const DynArray< Compiler_Type_Id > &members)
Creates a tuple type.
Compiler_Type_Id make_function_type(const DynArray< Compiler_Type_Id > ¶meters, const Compiler_Type_Id result)
Creates a function type.
Compiler_Type_Id character_type() const noexcept
Returns the preloaded Char type id.
void clear() noexcept
Drops user-created types and keeps the built-ins.
Compiler_Type_Id unit_type() const noexcept
Returns the preloaded Unit type id.
Compiler_Type_Id bool_type() const noexcept
Returns the preloaded Bool type id.
Compiler_Type_Id integer_type() const noexcept
Returns the preloaded Int type id.
Compiler_Type_Id make_struct_type(std::string name)
Creates a nominal struct type placeholder.
Structural unifier for compiler types.
Compiler_Unify_Result unify(const Compiler_Type_Id lhs, const Compiler_Type_Id rhs)
Attempts to unify lhs and rhs.
Compiler_Type_Id apply(const Compiler_Type_Id id)
Applies the current substitution to id.
void clear() noexcept
Clears substitutions and the last stored result.
Inference-oriented semantic pass for the MVP compiler front-end.
void predeclare_module_type_declarations(const Compiler_Module *module)
const Compiler_Semantic_Analyzer & semantic_analysis() const noexcept
Returns the base name-resolution pass used by the analyzer.
DynArray< Compiler_Expr_Type_Assignment > expr_types
const Compiler_Type_Unifier & type_unifier() const noexcept
Returns the internal unifier state.
void remember_function_annotation_type_variables(const Compiler_Function_Decl *function, const DynArray< Compiler_Type_Name_Binding > &type_names)
void analyze_module(const Compiler_Module *module)
Runs the typed semantic analysis for module.
static bool contains_type_id(const DynArray< Compiler_Type_Id > &values, const Compiler_Type_Id target) noexcept
Compiler_Type_Id let_type(const Compiler_Let_Stmt *stmt) const noexcept
Returns the inferred type of one let binding, or 0 if unknown.
Compiler_Type_Id find_function_type(const Compiler_Function_Decl *function) const
DynArray< Compiler_Function_Annotation_Type_Variable > function_annotation_type_variables
void record_let_type(const Compiler_Let_Stmt *stmt, const Compiler_Type_Id type_id)
DynArray< Compiler_Let_Type_Assignment > let_types
void analyze_block(const Compiler_Block_Stmt *block, const Compiler_Type_Id current_return_type, const Compiler_Function_Decl *current_function, bool &saw_return)
Compiler_Type_Id instantiate_binding(const Compiler_Value_Binding &binding)
void collect_free_type_variables(const Compiler_Type_Id type_id, DynArray< Compiler_Type_Id > &free_variables)
Compiler_Type_Id resolve_builtin_type_name(const std::string &name) const noexcept
Compiler_Type_Id lookup_type_name(const std::string &name, const DynArray< Compiler_Type_Name_Binding > &bindings) const noexcept
void clear() noexcept
Clears all inferred state and substitutions.
Compiler_Type_Id resolve_alias_binding(Compiler_Module_Type_Binding &binding, const Source_Span &span)
Compiler_Type_Id analyze_expr(const Compiler_Expr *expr)
Compiler_Type_Id inferred_type(const Compiler_Expr *expr) const noexcept
Returns the inferred type of one expression, or 0 if unknown.
bool validate_unique_member_name(const DynArray< std::string > &names, const std::string &candidate, const Source_Span &span, const std::string &what, const std::string &owner)
Compiler_Type_Id function_type(const Compiler_Function_Decl *function) const noexcept
Returns the inferred type of one function, or 0 if unknown.
void analyze_stmt(const Compiler_Stmt *stmt, const Compiler_Type_Id current_return_type, const Compiler_Function_Decl *current_function, bool &saw_return)
Compiler_Type_Id resolve_module_type_name(const std::string &name, const Source_Span &span)
DynArray< Compiler_Module_Type_Binding > module_type_bindings
Compiler_Type_Scheme generalize_type(const Compiler_Type_Id type_id, const DynArray< Compiler_Type_Id > &explicit_quantified_variables={})
static bool contains_name(const DynArray< std::string > &names, const std::string &target) noexcept
Compiler_Type_Id parameter_type(const Compiler_Function_Decl *function, const size_t index) const noexcept
Returns the inferred type of one parameter, or 0 if unknown.
Compiler_Typed_Semantic_Analyzer(Diagnostic_Engine *dx=nullptr, const Compiler_Typed_Semantic_Options &opts={})
Constructs a typed semantic analyzer.
void collect_binding_free_type_variables(const Compiler_Value_Binding &binding, DynArray< Compiler_Type_Id > &free_variables)
DynArray< Compiler_Function_Type_Assignment > function_types
Compiler_Type_Context types
bool insert_binding(const std::string &name, const Compiler_Value_Binding &binding)
void resolve_module_type_declaration(const Compiler_Type_Decl *decl)
bool require_unify(const Compiler_Type_Id lhs, const Compiler_Type_Id rhs, const Source_Span &span, const std::string &code, const std::string &prefix)
bool is_invalid_type(const Compiler_Type_Id id) const noexcept
Compiler_Module_Type_Binding * find_module_type_binding(const std::string &name) noexcept
DynArray< Compiler_Param_Type_Assignment > param_types
Compiler_Type_Id fresh_type()
Scope< std::string, Compiler_Value_Binding > scopes
static void append_unique_type_id(DynArray< Compiler_Type_Id > &values, const Compiler_Type_Id target)
Compiler_Type_Id declared_type(const std::string &name) const noexcept
Returns one declared module type by name, or 0 if unknown.
Compiler_Type_Id lookup_name_type(const std::string &name, const Source_Span &span)
Diagnostic_Engine * diagnostics
void resolve_module_type_declarations(const Compiler_Module *module)
void emit_error(const Source_Span &span, const std::string &code, const std::string &message, const std::string ¬e="", const std::string &help="") const
Compiler_Type_Id resolve_type_annotation(const Compiler_Type_Expr *type_expr, DynArray< Compiler_Type_Name_Binding > &type_names, const bool allow_fresh_type_variables=true)
DynArray< Compiler_Active_Binding > active_bindings
void record_param_type(const Compiler_Function_Decl *function, const size_t index, const Compiler_Type_Id type_id)
void analyze_function(const Compiler_Function_Decl *function)
const Compiler_Module_Type_Binding * find_module_type_binding(const std::string &name) const noexcept
std::string dump_inference() const
Dumps inferred function, parameter, and binding types.
Compiler_Type_Id predeclare_function(const Compiler_Function_Decl *function)
Compiler_Type_Id instantiate_type(const Compiler_Type_Id type_id, const DynArray< Compiler_Type_Id > &quantified_variables, DynArray< Compiler_Type_Id > &originals, DynArray< Compiler_Type_Id > &replacements)
void collect_environment_free_type_variables(DynArray< Compiler_Type_Id > &free_variables)
void seed_function_annotation_type_variables(const Compiler_Function_Decl *function, DynArray< Compiler_Type_Name_Binding > &type_names) const
DynArray< size_t > scope_markers
Compiler_Typed_Semantic_Options options
const Compiler_Type_Context & type_context() const noexcept
Returns the internal type context.
Compiler_Semantic_Analyzer base_semantic
void record_expr_type(const Compiler_Expr *expr, const Compiler_Type_Id type_id)
void record_function_type(const Compiler_Function_Decl *function, const Compiler_Type_Id type_id)
Compiler_Type_Unifier unifier
void normalize_recorded_types()
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_Builder & help(const std::string &msg)
Appends a help line.
Diagnostic_Builder & note(const std::string &msg)
Appends a note line.
Diagnostic accumulator and renderer.
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 pop()
Remove the last item of array (as if this was a stack)
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.
Lexical scope stack for Key to Value associations.
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Main namespace for Aleph-w library functions.
@ Grouping
Parenthesized expression.
@ Unary
Prefix unary operation (e.g., -x, !p).
@ Identifier
Variable or function name reference.
@ Integer_Literal
Numeric integer constant.
@ Invalid
Placeholder for malformed expressions.
@ Char_Literal
Character constant.
@ Binary
Infix binary operation (e.g., x + y).
@ Call
Function or method call.
@ String_Literal
String constant.
@ Bool_Literal
Boolean constant (true/false).
const char * compiler_token_kind_name(Compiler_Token_Kind kind)
Returns a human-readable name for a token kind.
void message(const char *file, int line, const char *format,...)
Print an informational message with file and line info.
@ While
Loop while a condition is true.
@ Invalid
Placeholder for malformed statements.
@ Expr
Expression evaluated for side effects (e.g., assignment, call).
@ If
Conditional execution.
@ Return
Exit current function with an optional value.
@ Continue
Skip to the next iteration of the innermost loop.
@ Let
Variable declaration and optional initialization.
@ Block
Scoped sequence of statements.
@ Break
Immediate exit from the innermost loop.
@ Invalid
Placeholder for malformed type declarations.
@ Struct
Nominal struct declaration.
@ Enum
Nominal enum declaration.
@ Alias
Transparent type alias declaration.
and
Check uniqueness with explicit hash + equality functors.
std::string code(Node *root)
Compute a string with the Lukasiewicz`s word of a tree.
static void prefix(Node *root, DynList< Node * > &acc)
@ Named
Named type such as Int or T.
@ Invalid
Placeholder for malformed type syntax.
@ Function
Function type such as fn(Int) -> Bool.
@ Tuple
Tuple type such as (Int, Bool).
Node representing an infix binary operation.
Node representing a braced sequence of statements.
Node representing a function or method call.
Nominal top-level enum declaration with unit variants.
Node representing an expression evaluated as a statement.
Compiler_Expr * expr
The expression being evaluated.
Recorded inferred type for one expression node.
Compiler_Type_Id type_id
Inferred or constrained type.
const Compiler_Expr * expr
Expression node.
Abstract base class for expression nodes.
Compiler_Expr_Kind kind
Specific expression type.
Node representing a top-level function declaration.
Source_Span name_span
Location of the function name token.
std::string name
Function name.
DynArray< Compiler_Param > parameters
Ordered list of parameters.
Compiler_Type_Expr * return_annotation
Optional declared return type.
Compiler_Block_Stmt * body
Scoped body of the function.
Recorded inferred type for one function declaration.
const Compiler_Function_Decl * function
Function declaration.
Compiler_Type_Id type_id
Inferred function type.
Function type syntax such as fn(Int, T) -> Bool.
Node representing an expression explicitly wrapped in parentheses.
Node representing a named identifier reference.
Node representing a conditional branch.
Node representing a local variable binding.
Recorded inferred type for one let binding.
Compiler_Type_Id type_id
Binding type.
const Compiler_Let_Stmt * stmt
Let statement node.
Node representing a complete translation unit or module.
DynArray< Compiler_Type_Decl * > type_declarations
Top-level type declarations.
DynArray< Compiler_Stmt * > statements
Optional top-level code.
DynArray< Compiler_Function_Decl * > functions
Top-level function definitions.
Named type syntax such as Int, Bool, or T.
Recorded inferred type for one function parameter.
const Compiler_Function_Decl * function
Owner function.
size_t index
Parameter index inside the function.
Compiler_Type_Id type_id
Parameter type.
Node representing a return from the current function.
Compiler_Expr * value
Optional value being returned.
Options controlling semantic analyzer behavior.
Abstract base class for statement nodes.
Compiler_Stmt_Kind kind
Specific statement type.
Nominal top-level struct declaration.
Tuple type syntax such as (Int, Bool).
Transparent top-level type alias declaration.
Compiler_Type_Expr * aliased_type
Aliased target type expression.
Abstract base class for top-level type declarations.
Abstract base class for parsed type-annotation syntax.
Compiler_Type_Id result_type
Function return type, or 0.
Compiler_Value_Binding binding
const Compiler_Function_Decl * function
const Compiler_Type_Alias_Decl * alias_decl
DynArray< Compiler_Type_Id > quantified_variables
Compiler_Type_Scheme scheme
Options controlling the typed semantic pass.
bool infer_unit_from_missing_return
Constrain functions with no explicit return to Unit.
Compiler_Semantic_Options semantic_options
Options forwarded to the base semantic pass.
bool run_base_semantic_checks
Run Compiler_Sema.H before typing.
Node representing a prefix unary operation.
Node representing a while-loop.
Half-open byte range inside a source file.
Equality constraints and type unification helpers for compiler work.
Lexical scope management using frame stacks.