| Crates.io | runmat-hir |
| lib.rs | runmat-hir |
| version | 0.2.8 |
| created_at | 2025-10-15 04:18:30.203464+00 |
| updated_at | 2025-12-22 21:36:14.081773+00 |
| description | High-level IR for RunMat with type inference and lowering utilities |
| homepage | https://runmat.org |
| repository | https://github.com/runmat-org/runmat |
| max_upload_size | |
| id | 1883742 |
| size | 186,199 |
High-level Intermediate Representation for MATLAB code. HIR is the semantic hub between parsing and execution (interpreter/JIT). It resolves identifiers to VarIds, attaches static types, normalizes constructs, and runs early semantic validations so downstream components can be simpler and faster.
VarId(usize): stable variable identifiers after name bindingType (from runmat-builtins):
Int, Num, Bool, StringTensor { shape: Option<Vec<Option<usize>>> } (column-major semantics)Cell { element_type: Option<Box<Type>>, length: Option<usize> }Function { params: Vec<Type>, returns: Box<Type> }Struct { known_fields: Option<Vec<String>> } (inference-only)Void, Unknown, Union(Vec<Type>)HirExpr { kind, ty } (selected variants):
Number, String, Var(VarId), ConstantUnary, BinaryTensor, Cell, Range, Colon, EndIndex, IndexCellFuncCall, FuncHandle, AnonFunc, Member, MemberDynamic, MethodCallMetaClass("pkg.Class")HirStmt (selected variants):
ExprStmt(expr, suppressed) (semicolon suppression)Assign(VarId, expr, suppressed)MultiAssign(Vec<Option<VarId>>, expr, suppressed) with ~ as NoneAssignLValue(HirLValue, expr, suppressed) where HirLValue ∈ { Var, Member, MemberDynamic, Index, IndexCell }If, While, For, Switch, TryCatchFunction { name, params, outputs, body, has_varargin, has_varargout }, Global, PersistentBreak, Continue, ReturnClassDef { name, super_class, members }Import { path: Vec<String>, wildcard: bool }HirClassMember: Properties, Methods, Events, Enumeration, Arguments (carry parser::Attr attributes)HirProgram { body }Ctx manages scopes, binds names to VarId, and maintains var_types for flow typing.FuncCall(name, []).Index/IndexCell and FuncCall distinct.HirLValue for dot/paren/brace writes. Plain A(…) = v is AssignLValue.Function statements record has_varargin/has_varargout flags.ClassDef lowers structurally into HirClassMember blocks with attributes preserved.Import lowers to a dedicated HirStmt::Import (no runtime effect; used by name resolution/validation).?Qualified.Name lowers to HirExprKind::MetaClass("Qualified.Name"); postfix is handled in the compiler.arguments ... end blocks (when present) are parsed; names are accepted and exposed to later validation. Constraint checking (types/defaults/ranges) is enforced at HIR/VM time rather than parsing time.validate_classdefs(&HirProgram) runs during lower():
Abstract ∧ Sealed invalid; Properties: Static ∧ Dependent invalid; Access/GetAccess/SetAccess values limited to public|private)Events, Enumeration, and Arguments (unique names; no conflicts with props/methods)collect_imports(&HirProgram)normalize_imports(&HirProgram) -> Vec<NormalizedImport { path, wildcard, unqualified }]validate_imports(&HirProgram) checks duplicates and ambiguity among specifics with the same unqualified nameNum/String/Bool.Tensor, result is Tensor (shape may unify when known).Tensor.Unknown by default (value-dependent at runtime).String type.Two complementary passes exist:
infer_function_output_types(&HirProgram) -> HashMap<String, Vec<Type>>
analyze_stmts(outputs, …, func_returns) whose env joins propagate return typesinfer_function_variable_types(&HirProgram) -> HashMap<String, HashMap<VarId, Type>
FuncCall[a,b]=f(...) at callers.Type::Struct { known_fields: Option<Vec<String>> } to conservatively track observed fields on variables.s.field = expr marks s as Struct and adds "field" to known_fields.isfield(s, 'x')ismember('x', fieldnames(s)) or ismember(fieldnames(s), 'x')strcmp(fieldnames(s), 'x') / strcmpi(…), including any(strcmp(…)) or all(strcmp(…))&& or & are traversed; negations are ignored (no refinement)Type::unify for Structs.[a,b] = f(...) is typed per-position using the callee's return summary when available.[~,b] = f(...) are handled by storing None in the LHS vector and skipping the slot.runmat-builtins).MultiAssign contexts.remapping::create_function_var_map, create_complete_function_var_mapremapping::remap_function_body / remap_stmt / remap_expr to rewrite VarIds for local execution framesremapping::collect_function_variables scans bodies to compute complete mapslower(&AstProgram) -> Result<HirProgram, String>: lowers AST, runs return-summary inference (for seeding), then validates classeslower_with_context / lower_with_full_context: lowering for REPL with preexisting variables/functionsvalidate_classdefs, collect_imports, normalize_imports, validate_importsinfer_function_output_types, infer_function_variable_types~ placeholderarguments ... end declared names/constraints (when available from parser) and surface to runtime validation. Current parser accepts names; HIR will add optional metadata structs without breaking format.~; HIR enforces shape semantics at runtime. Additional unit tests exist; no further work is blocking.MATLAB:
function y = f(s)
if isfield(s, 'x') && any(strcmp(fieldnames(s), 'y'))
s.y = 1;
end
y = g(s.x);
end
HIR sketch:
Function { name: "f", params: [s], outputs: [y], ... }
If { cond: FuncCall("isfield", [Var(s), String('x')]) && any(strcmp(fieldnames(s),'y')), then: [ AssignLValue(Member(Var(s),'y'), Number(1)) ] }
Assign(Var(y), FuncCall("g", [Member(Var(s), "x")]))
Return summaries infer type of g's first output if available; variable analysis refines s as a Struct with fields {x,y} along the then-branch.