diff --git a/ir/BUILD b/ir/BUILD index b96669c8..339404ee 100644 --- a/ir/BUILD +++ b/ir/BUILD @@ -105,6 +105,7 @@ cc_library( "//parser:parse_tree", "//parser:parse_tree_node_kind_xmacro", "//type", + "@asoffer_jasmin//jasmin:execute", "@asoffer_jasmin//jasmin:value_stack", "@asoffer_nth//nth/debug", "@asoffer_nth//nth/debug/log", diff --git a/ir/builtin_module.cc b/ir/builtin_module.cc index 3532dd7d..bf1214d3 100644 --- a/ir/builtin_module.cc +++ b/ir/builtin_module.cc @@ -30,6 +30,12 @@ nth::NoDestructor Foreign([] { return f; }()); +nth::NoDestructor ForeignType([] { + IrFunction f(1, 1); + f.append(); + return f; +}()); + Module BuiltinModule(GlobalFunctionRegistry& registry) { uint32_t next_id = 0; @@ -47,10 +53,11 @@ Module BuiltinModule(GlobalFunctionRegistry& registry) { registry.Register(FunctionId(ModuleId::Builtin(), LocalFunctionId(next_id++)), &*PrintFn); - m.Insert(resources.IdentifierIndex("foreign"), - {.qualified_type = type::QualifiedType( - type::Qualifier::Constant(), type::GenericFunction(nullptr)), - .value = {}}); + m.Insert( + resources.IdentifierIndex("foreign"), + {.qualified_type = type::QualifiedType( + type::Qualifier::Constant(), type::GenericFunction(&*ForeignType)), + .value = {}}); registry.Register(FunctionId(ModuleId::Builtin(), LocalFunctionId(next_id++)), &*Foreign); diff --git a/ir/emit.cc b/ir/emit.cc index 5d9fc31e..bbb40f8e 100644 --- a/ir/emit.cc +++ b/ir/emit.cc @@ -179,6 +179,7 @@ void EmitContext::Push(jasmin::Value v, type::Type t) { void EmitIr(nth::interval node_range, EmitContext& context) { ParseTree::Node::Index start = node_range.lower_bound(); for (auto const& [range, value_stack] : context.constants) { + if (range.lower_bound() < start) { continue; } EmitNonConstant(nth::interval(start, range.lower_bound()), context); // TODO: This type is wrong. for (jasmin::Value const& v : value_stack) { context.Push(v, type::Bool); } @@ -188,15 +189,14 @@ void EmitIr(nth::interval node_range, EmitContext& conte context.function_stack.back()->append(); } -void Evaluate(nth::interval subtree, - ParseTree const& tree, - DependentModules const& modules NTH_ATTRIBUTE(lifetimebound), - jasmin::ValueStack& value_stack) { +void EmitContext::Evaluate(nth::interval subtree, + jasmin::ValueStack& value_stack) { IrFunction f(0, 1); - EmitContext context(tree, modules, f); - EmitIr(subtree, context); - context.function_stack.back()->append(); + function_stack.push_back(&f); + EmitIr(subtree, *this); + f.append(); jasmin::Execute(f, value_stack); + function_stack.pop_back(); } } // namespace ic diff --git a/ir/emit.h b/ir/emit.h index 57fdd8db..0721e21d 100644 --- a/ir/emit.h +++ b/ir/emit.h @@ -32,6 +32,9 @@ struct EmitContext { void Push(jasmin::Value v, type::Type); + void Evaluate(nth::interval subtree, + jasmin::ValueStack& value_stack); + ParseTree::Node const& Node(ParseTree::Node::Index index) { return tree[index]; } @@ -69,11 +72,6 @@ struct EmitContext { void EmitIr(nth::interval node_range, EmitContext& context); -void Evaluate(nth::interval subtree, - ParseTree const& tree, - DependentModules const& modules NTH_ATTRIBUTE(lifetimebound), - jasmin::ValueStack& value_stack); - } // namespace ic #endif // ICARUS_IR_EMIT_H diff --git a/ir/ir.cc b/ir/ir.cc index 840c69c2..8ab3ead1 100644 --- a/ir/ir.cc +++ b/ir/ir.cc @@ -2,6 +2,7 @@ #include "common/string.h" #include "ir/module_id.h" +#include "jasmin/execute.h" #include "nth/debug/debug.h" #include "nth/debug/log/log.h" #include "type/type.h" @@ -199,6 +200,22 @@ void HandleParseTreeNodeCallExpression(ParseTree::Node::Index index, } else { NTH_UNIMPLEMENTED(); } + } else if (invocable_type.type().kind() == + type::Type::Kind::GenericFunction) { + jasmin::ValueStack value_stack; + for (auto iter = context.ChildIndices(index).begin(); + context.Node(*iter).kind != + ParseTree::Node::Kind::InvocationArgumentStart; + ++iter) { + context.emit.Evaluate(context.emit.tree.subtree_range(*iter), + value_stack); + } + + jasmin::Execute(*static_cast( + invocable_type.type().AsGenericFunction().data()), + value_stack); + context.type_stack.push_back(type::QualifiedType( + type::Qualifier::Constant(), value_stack.pop())); } else { NTH_UNIMPLEMENTED("{}") <<= {node}; } diff --git a/ir/ir.h b/ir/ir.h index f51f2f7f..750cd40b 100644 --- a/ir/ir.h +++ b/ir/ir.h @@ -21,6 +21,9 @@ struct IrContext { return emit.tree[index]; } + auto ChildIndices(ParseTree::Node::Index index) { + return emit.tree.child_indices(index); + } auto Children(ParseTree::Node::Index index) { return emit.tree.children(index); } @@ -31,12 +34,12 @@ struct IrContext { std::optional EvaluateAs(ParseTree::Node::Index subtree_root_index) { T result; nth::interval range = emit.tree.subtree_range(subtree_root_index); - auto [iter, inserted] = emit.constants.try_emplace(range); + jasmin::ValueStack value_stack; + emit.Evaluate(range, value_stack); + auto [iter, inserted] = emit.constants.try_emplace(range, std::move(value_stack)); NTH_REQUIRE((v.harden), inserted); - jasmin::ValueStack& value_stack = iter->second; - Evaluate(range, emit.tree, emit.modules, value_stack); if (IcarusDeserializeValue( - std::span(value_stack.begin(), value_stack.end()), result)) { + std::span(iter->second.begin(), iter->second.end()), result)) { return result; } else { return std::nullopt; diff --git a/type/type.cc b/type/type.cc index b827e8f6..ad0cb399 100644 --- a/type/type.cc +++ b/type/type.cc @@ -104,6 +104,10 @@ std::vector const& FunctionType::returns() const { return ic::type::returns->from_index(functions->from_index(data()).second); } +void const* GenericFunctionType::data() const { + return generic_function_types->from_index(BasicType::data()); +} + size_t JasminSize(Type t) { switch (t.kind()) { case Type::Kind::Primitive: return 1; diff --git a/type/type.h b/type/type.h index bbcee767..d6b3f98b 100644 --- a/type/type.h +++ b/type/type.h @@ -3,6 +3,9 @@ #include #include +#include +#include +#include #include namespace ic::type { @@ -208,6 +211,24 @@ struct FunctionType : internal_type::BasicType { ParametersType parameters() const; std::vector const& returns() const; + friend void NthPrint(auto& p, auto&fmt, FunctionType f) { + std::string_view separator = "("; + for (auto const& param : *f.parameters()) { + p.write(std::exchange(separator, ", ")); + fmt(p, param.name); + p.write(": "); + fmt(p, param.type); + } + std::span returns = f.returns(); + p.write(returns.size() != 1 ? ") -> (" : ") -> "); + separator = ""; + for (auto const& r: f.returns()) { + p.write(std::exchange(separator, ", ")); + fmt(p, r); + } + if (returns.size() != 1) { p.write(")"); } + } + private: friend Type; friend FunctionType Function(ParametersType, std::vector&&); @@ -293,6 +314,8 @@ struct SliceType : internal_type::BasicType { SliceType Slice(Type t); struct GenericFunctionType : internal_type::BasicType { + void const* data() const; + private: friend Type; friend GenericFunctionType GenericFunction(void const* fn); diff --git a/type/type_system.proto b/type/type_system.proto new file mode 100644 index 00000000..1de308ef --- /dev/null +++ b/type/type_system.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package type; + +message TypeProto { + enum Kind { + UNKNOWN = 0; + PRIMITIVE = 1; + POINTER = 2; + BUFFER_POINTER = 3; + SLICE = 4; + FUNCTION = 5; + PATTERN = 6; + } + Kind kind = 1; + uint32 index = 2; +} + +message ParameterTypeProto { + TypeProto type = 1; +} + +message FunctionTypeProto { + repeated ParameterTypeProto parameters = 1; + repeated TypeProto returns = 2; +} + +message TypeSystem { + repeated FunctionTypeProto functions = 1; +}