Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Treat responsibilities like other parameters #645

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
15 changes: 10 additions & 5 deletions compiler/cli/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ pub(crate) fn run(options: Options) -> ProgramResult {

debug!("Running main function.");
// TODO: Add more environment stuff.
let stdout = Handle::new(&mut heap, 1);
let stdin = Handle::new(&mut heap, 0);
let stdout = Handle::new(&mut heap, 2);
let stdin = Handle::new(&mut heap, 1);
let environment = Struct::create_with_symbol_keys(
&mut heap,
true,
Expand All @@ -98,23 +98,28 @@ pub(crate) fn run(options: Options) -> ProgramResult {
lir.clone(),
heap,
main,
&[environment],
platform,
&[environment, platform.into()],
StackTracer::default(),
);

let result = loop {
match vm.run_forever() {
StateAfterRunForever::CallingHandle(mut call) => {
if call.handle == stdout {
let message = call.arguments[0];
let [message, _responsible] = call.arguments[..] else {
unreachable!()
};

match message.into() {
Data::Text(text) => println!("{}", text.get()),
_ => info!("Non-text value sent to stdout: {message:?}"),
}
vm = call.complete(Tag::create_nothing());
} else if call.handle == stdin {
let [_responsible] = call.arguments[..] else {
unreachable!()
};

print!(">> ");
io::stdout().flush().unwrap();
let input = {
Expand Down
3 changes: 2 additions & 1 deletion compiler/frontend/src/builtin_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ impl BuiltinFunction {

#[must_use]
pub const fn num_parameters(&self) -> usize {
match self {
// Responsibility parameter.
1 + match self {
Self::Equals => 2,
Self::FunctionRun => 1,
Self::GetArgumentCount => 1,
Expand Down
86 changes: 38 additions & 48 deletions compiler/frontend/src/hir_to_mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,15 @@ fn generate_needs_function(body: &mut BodyBuilder) -> Id {
let true_tag = body.push_bool(true);
let false_tag = body.push_bool(false);
let is_condition_true =
body.push_call(builtin_equals, vec![condition, true_tag], needs_code);
body.push_call(builtin_equals, vec![condition, true_tag, needs_code]);
let is_condition_bool = body.push_if_else(
&needs_id.child("isConditionTrue"),
is_condition_true,
|body| {
body.push_reference(true_tag);
},
|body| {
body.push_call(builtin_equals, vec![condition, false_tag], needs_code);
body.push_call(builtin_equals, vec![condition, false_tag, needs_code]);
},
needs_code,
);
Expand All @@ -122,12 +122,11 @@ fn generate_needs_function(body: &mut BodyBuilder) -> Id {

// Make sure the reason is a text.
let builtin_type_of = body.push_builtin(BuiltinFunction::TypeOf);
let type_of_reason = body.push_call(builtin_type_of, vec![reason], responsible_for_call);
let type_of_reason = body.push_call(builtin_type_of, vec![reason, responsible_for_call]);
let text_tag = body.push_tag("Text".to_string(), None);
let is_reason_text = body.push_call(
builtin_equals,
vec![type_of_reason, text_tag],
responsible_for_call,
vec![type_of_reason, text_tag, responsible_for_call],
);
body.push_if_else(
&needs_id.child("isReasonText"),
Expand Down Expand Up @@ -270,8 +269,7 @@ impl<'a> LoweringContext<'a> {
let one = body.push_int(1.into());
let reason = body.push_call(
list_get_function,
vec![pattern_result, one],
responsible,
vec![pattern_result, one, responsible],
);

body.push_panic(reason, responsible);
Expand All @@ -290,7 +288,7 @@ impl<'a> LoweringContext<'a> {
let list_get = body.push_builtin(BuiltinFunction::ListGet);
let index = body.push_int((identifier_id.0 + 1).into());
let responsible = body.push_hir_id(hir_id.clone());
body.push_call(list_get, vec![result, index], responsible)
body.push_call(list_get, vec![result, index, responsible])
}
}
hir::Expression::Match { expression, cases } => {
Expand Down Expand Up @@ -346,22 +344,21 @@ impl<'a> LoweringContext<'a> {
function,
arguments,
} => {
let responsible = body.push_hir_id(hir_id.clone());
let call_site = body.push_hir_id(hir_id.clone());
let arguments = arguments
.iter()
.map(|argument| self.mapping[argument])
.chain([call_site])
.collect_vec();

if self.tracing.calls.is_enabled() {
let hir_call = body.push_hir_id(hir_id.clone());
body.push(Expression::TraceCallStarts {
hir_call,
hir_call: call_site,
function: self.mapping[function],
arguments: arguments.clone(),
responsible,
});
}
let call = body.push_call(self.mapping[function], arguments, responsible);
let call = body.push_call(self.mapping[function], arguments);
if self.tracing.calls.is_enabled() {
body.push(Expression::TraceCallEnds { return_value: call });
body.push_reference(call)
Expand Down Expand Up @@ -389,8 +386,8 @@ impl<'a> LoweringContext<'a> {
self.mapping[condition],
self.mapping[reason],
responsible_for_needs,
responsible,
],
responsible,
)
}
hir::Expression::Error { errors, .. } => {
Expand Down Expand Up @@ -474,8 +471,7 @@ impl<'a> LoweringContext<'a> {
let one = body.push_int(1.into());
let reason = body.push_call(
list_get_function,
vec![pattern_result, one],
responsible_for_match,
vec![pattern_result, one, responsible_for_match],
);
no_match_reasons.push(reason);

Expand All @@ -492,8 +488,12 @@ impl<'a> LoweringContext<'a> {
});
body.push_call(
builtin_if_else,
vec![is_match, then_function, else_function],
responsible_for_match,
vec![
is_match,
then_function,
else_function,
responsible_for_match,
],
)
}
}
Expand Down Expand Up @@ -544,18 +544,17 @@ impl PatternLoweringContext {
body.push_builtin(BuiltinFunction::TagWithoutValue);
let actual_symbol = body.push_call(
builtin_tag_without_value,
vec![expression],
self.responsible,
vec![expression, self.responsible],
);
let expected_symbol = body.push_tag(symbol.clone(), None);
self.compile_equals(body, expected_symbol, actual_symbol, |body| {
let builtin_tag_has_value = body.push_builtin(BuiltinFunction::TagHasValue);
let actual_has_value = body.push_call(builtin_tag_has_value, vec![expression], self.responsible);
let actual_has_value = body.push_call(builtin_tag_has_value, vec![expression, self.responsible]);
let expected_has_value = body.push_bool(value.is_some());
self.compile_equals(body, expected_has_value, actual_has_value, |body| {
if let Some(value) = value {
let builtin_tag_get_value = body.push_builtin(BuiltinFunction::TagGetValue);
let actual_value = body.push_call(builtin_tag_get_value, vec![expression], self.responsible);
let actual_value = body.push_call(builtin_tag_get_value, vec![expression, self.responsible]);
self.compile(body, actual_value, value);
} else {
self.push_match(body, vec![]);
Expand All @@ -567,9 +566,9 @@ impl PatternLoweringContext {
]
} else {
let builtin_tag_get_value = body.push_builtin(BuiltinFunction::TagGetValue);
let actual_value = body.push_call(builtin_tag_get_value, vec![expression], self.responsible);
let actual_value = body.push_call(builtin_tag_get_value, vec![expression, self.responsible]);
let builtin_to_debug_text = body.push_builtin(BuiltinFunction::ToDebugText);
let actual_value_text = body.push_call(builtin_to_debug_text, vec![actual_value], self.responsible);
let actual_value_text = body.push_call(builtin_to_debug_text, vec![actual_value, self.responsible]);
vec![
body.push_text("Expected tag to not have a value, but it has one: `".to_string()),
actual_value_text,
Expand Down Expand Up @@ -598,7 +597,7 @@ impl PatternLoweringContext {
let expected = body.push_int(list.len().into());
let builtin_list_length = body.push_builtin(BuiltinFunction::ListLength);
let actual_length =
body.push_call(builtin_list_length, vec![expression], self.responsible);
body.push_call(builtin_list_length, vec![expression, self.responsible]);
self.compile_equals(
body,
expected,
Expand All @@ -614,8 +613,7 @@ impl PatternLoweringContext {
let index = body.push_int(index.into());
let item = body.push_call(
builtin_list_get,
vec![expression, index],
self.responsible,
vec![expression, index, self.responsible],
);
let result = self.compile(body, item, item_pattern);
(result, item_pattern.captured_identifier_count())
Expand Down Expand Up @@ -651,8 +649,7 @@ impl PatternLoweringContext {
let key = self.compile_pattern_to_key_expression(body, key_pattern);
let has_key = body.push_call(
builtin_struct_has_key,
vec![expression, key],
self.responsible,
vec![expression, key, self.responsible,],
);

let result = body.push_if_else(
Expand All @@ -661,8 +658,7 @@ impl PatternLoweringContext {
|body| {
let value = body.push_call(
builtin_struct_get,
vec![expression, key],
self.responsible,
vec![expression, key, self.responsible],
);
self.compile(body, value, value_pattern);
},
Expand All @@ -672,14 +668,12 @@ impl PatternLoweringContext {

let key_as_text = body.push_call(
to_debug_text,
vec![key],
self.responsible,
vec![key, self.responsible],
);

let struct_as_text = body.push_call(
to_debug_text,
vec![expression],
self.responsible,
vec![expression, self.responsible],
);

let reason_parts = vec![
Expand Down Expand Up @@ -736,7 +730,7 @@ impl PatternLoweringContext {
let Some(index) = index else { return body.push_reference(nothing); };

let index = body.push_int((1 + index).into());
body.push_call(list_get_function, vec![result, index], self.responsible)
body.push_call(list_get_function, vec![result, index, self.responsible])
})
.collect();
self.push_match(body, captured_identifiers);
Expand Down Expand Up @@ -792,7 +786,7 @@ impl PatternLoweringContext {
{
let expected_type = body.push_tag(expected_type, None);
let builtin_type_of = body.push_builtin(BuiltinFunction::TypeOf);
let type_ = body.push_call(builtin_type_of, vec![expression], self.responsible);
let type_ = body.push_call(builtin_type_of, vec![expression, self.responsible]);
self.compile_equals(
body,
expected_type,
Expand Down Expand Up @@ -823,7 +817,7 @@ impl PatternLoweringContext {
E: FnOnce(&mut BodyBuilder, Id, Id) -> Vec<Id>,
{
let builtin_equals = body.push_builtin(BuiltinFunction::Equals);
let equals = body.push_call(builtin_equals, vec![expected, actual], self.responsible);
let equals = body.push_call(builtin_equals, vec![expected, actual, self.responsible]);

body.push_if_else(
&self.hir_id.child("equals"),
Expand All @@ -832,8 +826,8 @@ impl PatternLoweringContext {
|body| {
let to_debug_text = body.push_builtin(BuiltinFunction::ToDebugText);
let expected_as_text =
body.push_call(to_debug_text, vec![expected], self.responsible);
let actual_as_text = body.push_call(to_debug_text, vec![actual], self.responsible);
body.push_call(to_debug_text, vec![expected, self.responsible]);
let actual_as_text = body.push_call(to_debug_text, vec![actual, self.responsible]);
let reason_parts = reason_factory(body, expected_as_text, actual_as_text);
let reason = self.push_text_concatenate(body, reason_parts);
self.push_no_match(body, reason);
Expand Down Expand Up @@ -897,8 +891,7 @@ impl PatternLoweringContext {
let index = body.push_int((index + 1).into());
let captured_identifier = body.push_call(
list_get_function,
vec![return_value, index],
self.responsible,
vec![return_value, index, self.responsible],
);
captured_identifiers.push(captured_identifier);
}
Expand All @@ -920,8 +913,7 @@ impl PatternLoweringContext {
.reduce(|left, right| {
body.push_call(
builtin_text_concatenate,
vec![left, right],
self.responsible,
vec![left, right, self.responsible],
)
})
.unwrap()
Expand Down Expand Up @@ -952,16 +944,14 @@ impl BodyBuilder {
let zero = self.push_int(0.into());
let match_or_no_match_tag = self.push_call(
list_get_function,
vec![match_or_no_match, zero],
responsible,
vec![match_or_no_match, zero, responsible],
);

let equals_function = self.push_builtin(BuiltinFunction::Equals);
let match_tag = self.push_match_tag();
self.push_call(
equals_function,
vec![match_or_no_match_tag, match_tag],
responsible,
vec![match_or_no_match_tag, match_tag, responsible],
)
}

Expand Down
15 changes: 3 additions & 12 deletions compiler/frontend/src/lir/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ pub enum Expression {
Call {
function: Id,
arguments: Vec<Id>,
responsible: Id,
},

Panic {
Expand All @@ -54,7 +53,6 @@ pub enum Expression {
hir_call: Id,
function: Id,
arguments: Vec<Id>,
responsible: Id,
},

TraceCallEnds {
Expand Down Expand Up @@ -128,7 +126,6 @@ impl ToRichIr for Expression {
Self::Call {
function,
arguments,
responsible,
} => {
builder.push("call ", None, EnumSet::empty());
function.build_rich_ir(builder);
Expand All @@ -138,33 +135,27 @@ impl ToRichIr for Expression {
} else {
builder.push_children(arguments, " ");
}
builder.push(" (", None, EnumSet::empty());
responsible.build_rich_ir(builder);
builder.push(" is responsible)", None, EnumSet::empty());
}
Self::Panic {
reason,
responsible,
} => {
builder.push("panicking because ", None, EnumSet::empty());
reason.build_rich_ir(builder);
builder.push(" (", None, EnumSet::empty());
builder.push(", ", None, EnumSet::empty());
responsible.build_rich_ir(builder);
builder.push(" is at fault)", None, EnumSet::empty());
builder.push(" is at fault", None, EnumSet::empty());
}
Self::TraceCallStarts {
hir_call,
function,
arguments,
responsible,
} => {
builder.push("trace: start of call of ", None, EnumSet::empty());
function.build_rich_ir(builder);
builder.push(" with ", None, EnumSet::empty());
builder.push_children(arguments, " ");
builder.push(" (", None, EnumSet::empty());
responsible.build_rich_ir(builder);
builder.push(" is responsible, code is at ", None, EnumSet::empty());
builder.push(" (code is at ", None, EnumSet::empty());
hir_call.build_rich_ir(builder);
builder.push(")", None, EnumSet::empty());
}
Expand Down
Loading