Skip to content

Commit

Permalink
Fixes #966, #797 and other clean ups (#987)
Browse files Browse the repository at this point in the history
  • Loading branch information
afsalthaj authored Oct 3, 2024
1 parent 033576f commit a424cb9
Show file tree
Hide file tree
Showing 28 changed files with 1,253 additions and 724 deletions.
413 changes: 347 additions & 66 deletions golem-rib/src/compiler/byte_code.rs

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions golem-rib/src/compiler/desugar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,19 +261,19 @@ mod internal {
) -> Option<IfThenBranch> {
match pred_expr_inferred_type {
InferredType::Record(field_and_types) => {
// Resolution body is a list of expressions which grows (may be with some let bindings)
// Resolution body is a list of expressions which grows (maybe with some let bindings)
// as we recursively iterate over the bind patterns
// where bind patterns are {name: x, age: _, address : _ } in the case of `match record { {name: x, age: _, address : _ } ) =>`
// These will exist prior to the original resolution of a successful tuple match.
// These will exist prior to the original resolution of a successful record match.
let mut resolution_body = vec![];

// The conditions keep growing as we recursively iterate over the bind patterns
// and there are multiple conditions (if condition) for each element in the tuple
// and there are multiple conditions (if condition) for each element in the record.
let mut conditions = vec![];

// We assume pred-expr can be queried by field using Expr::select_field and we pick each element in the bind pattern
// We assume pred-expr can be queried by field using Expr::select_field, and we pick each element in the bind pattern
// to get the corresponding expr in pred-expr and keep recursively iterating until the record is completed.
// However there is no resolution body for each of this iteration, so we use an empty expression
// However, there is no resolution body for each of this iteration, so we use an empty expression
// and finally push the original resolution body once we fully build the conditions.
for (field, arm_pattern) in bind_patterns.iter() {
let new_pred = Expr::select_field(pred_expr.clone(), field);
Expand Down
12 changes: 8 additions & 4 deletions golem-rib/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ impl Expr {
matches!(self, Expr::Cond(_, _, _, _))
}

pub fn is_function_call(&self) -> bool {
matches!(self, Expr::Call(_, _, _))
}

pub fn is_match_expr(&self) -> bool {
matches!(self, Expr::PatternMatch(_, _, _))
}
Expand Down Expand Up @@ -419,10 +423,10 @@ impl Expr {
self.bind_types();
self.name_binding_pattern_match_variables();
self.name_binding_local_variables();
self.infer_function_types(function_type_registry)
.map_err(|x| vec![x])?;
self.infer_variants(function_type_registry);
self.infer_enums(function_type_registry);
self.infer_call_arguments_type(function_type_registry)
.map_err(|x| vec![x])?;
type_inference::type_inference_fix_point(Self::inference_scan, self)
.map_err(|x| vec![x])?;
self.unify_types()?;
Expand Down Expand Up @@ -452,11 +456,11 @@ impl Expr {
}

// At this point we simply update the types to the parameter type expressions and the call expression itself.
pub fn infer_function_types(
pub fn infer_call_arguments_type(
&mut self,
function_type_registry: &FunctionTypeRegistry,
) -> Result<(), String> {
type_inference::infer_function_types(self, function_type_registry)
type_inference::infer_call_arguments_type(self, function_type_registry)
}

pub fn push_types_down(&mut self) -> Result<(), String> {
Expand Down
18 changes: 14 additions & 4 deletions golem-rib/src/function_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,25 +476,35 @@ impl ParsedFunctionReference {
Self::RawResourceStaticMethod {
resource, method, ..
} => format!("[static]{resource}.{method}"),
ParsedFunctionReference::IndexedResourceConstructor { resource, .. } => {
Self::IndexedResourceConstructor { resource, .. } => {
format!("[constructor]{resource}")
}
ParsedFunctionReference::IndexedResourceMethod {
Self::IndexedResourceMethod {
resource, method, ..
} => {
format!("[method]{resource}.{method}")
}
ParsedFunctionReference::IndexedResourceStaticMethod {
Self::IndexedResourceStaticMethod {
resource, method, ..
} => {
format!("[static]{resource}.{method}")
}
ParsedFunctionReference::IndexedResourceDrop { resource, .. } => {
Self::IndexedResourceDrop { resource, .. } => {
format!("[drop]{resource}")
}
}
}

pub fn resource_method_name(&self) -> Option<String> {
match self {
Self::IndexedResourceStaticMethod { method, .. }
| Self::RawResourceMethod { method, .. }
| Self::RawResourceStaticMethod { method, .. }
| Self::IndexedResourceMethod { method, .. } => Some(method.clone()),
_ => None,
}
}

pub fn method_as_static(&self) -> Option<ParsedFunctionReference> {
match self {
Self::RawResourceMethod { resource, method } => Some(Self::RawResourceStaticMethod {
Expand Down
30 changes: 21 additions & 9 deletions golem-rib/src/inferred_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,25 @@ impl InferredType {
}
}
}

pub fn from_variant_cases(type_variant: &TypeVariant) -> InferredType {
let cases = type_variant
.cases
.iter()
.map(|name_type_pair| {
(
name_type_pair.name.clone(),
name_type_pair.typ.clone().map(|t| t.into()),
)
})
.collect();

InferredType::Variant(cases)
}

pub fn from_enum_cases(type_enum: &TypeEnum) -> InferredType {
InferredType::Enum(type_enum.cases.clone())
}
}

impl From<AnalysedType> for InferredType {
Expand Down Expand Up @@ -1146,22 +1165,15 @@ impl From<AnalysedType> for InferredType {
.collect(),
),
AnalysedType::Flags(vs) => InferredType::Flags(vs.names),
AnalysedType::Enum(vs) => InferredType::Enum(vs.cases),
AnalysedType::Enum(vs) => InferredType::from_enum_cases(&vs),
AnalysedType::Option(t) => InferredType::Option(Box::new((*t.inner).into())),
AnalysedType::Result(golem_wasm_ast::analysis::TypeResult { ok, err, .. }) => {
InferredType::Result {
ok: ok.map(|t| Box::new((*t).into())),
error: err.map(|t| Box::new((*t).into())),
}
}
AnalysedType::Variant(vs) => InferredType::Variant(
vs.cases
.into_iter()
.map(|name_type_pair| {
(name_type_pair.name, name_type_pair.typ.map(|t| t.into()))
})
.collect(),
),
AnalysedType::Variant(vs) => InferredType::from_variant_cases(&vs),
AnalysedType::Handle(golem_wasm_ast::analysis::TypeHandle { resource_id, mode }) => {
InferredType::Resource {
resource_id: resource_id.0,
Expand Down
11 changes: 11 additions & 0 deletions golem-rib/src/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,14 @@ pub async fn interpret(
let mut interpreter = Interpreter::new(rib_input, function_invoke);
interpreter.run(rib.clone()).await
}

// This function can be used for those the Rib Scripts
// where there are no side effecting function calls.
// It is recommended to use `interpret` over `interpret_pure` if you are unsure.
pub async fn interpret_pure(
rib: &RibByteCode,
rib_input: &HashMap<String, TypeAnnotatedValue>,
) -> Result<RibInterpreterResult, String> {
let mut interpreter = Interpreter::pure(rib_input.clone());
interpreter.run(rib.clone()).await
}
7 changes: 4 additions & 3 deletions golem-rib/src/interpreter/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,21 @@ impl RibInterpreterResult {
pub fn get_bool(&self) -> Option<bool> {
match self {
RibInterpreterResult::Val(TypeAnnotatedValue::Bool(bool)) => Some(*bool),
_ => None,
RibInterpreterResult::Val(_) => None,
RibInterpreterResult::Unit => None,
}
}
pub fn get_val(&self) -> Option<TypeAnnotatedValue> {
match self {
RibInterpreterResult::Val(val) => Some(val.clone()),
_ => None,
RibInterpreterResult::Unit => None,
}
}

pub fn get_literal(&self) -> Option<LiteralValue> {
match self {
RibInterpreterResult::Val(val) => val.get_literal(),
_ => None,
RibInterpreterResult::Unit => None,
}
}

Expand Down
77 changes: 40 additions & 37 deletions golem-rib/src/interpreter/rib_interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ impl Interpreter {
}
}

pub fn from_input(env: HashMap<String, TypeAnnotatedValue>) -> Self {
// Interpreter that's not expected to call a side-effecting function call.
// All it needs is environment with the required variables to evaluate the Rib script
pub fn pure(env: HashMap<String, TypeAnnotatedValue>) -> Self {
Interpreter {
stack: InterpreterStack::new(),
env: InterpreterEnv::from_input(env),
Expand Down Expand Up @@ -140,8 +142,8 @@ impl Interpreter {
internal::run_create_function_name_instruction(site, function_type, self)?;
}

RibIR::InvokeFunction(arity, _) => {
internal::run_call_instruction(arity, self).await?;
RibIR::InvokeFunction(arg_size, _) => {
internal::run_call_instruction(arg_size, self).await?;
}

RibIR::PushVariant(variant_name, analysed_type) => {
Expand Down Expand Up @@ -335,7 +337,7 @@ mod internal {
.map(|interpreter_result| {
interpreter_result
.get_val()
.ok_or("Failed to get value from the stack".to_string())
.ok_or("Internal Error: Failed to construct list".to_string())
})
.collect::<Result<Vec<TypeAnnotatedValue>, String>>()?;

Expand Down Expand Up @@ -363,12 +365,13 @@ mod internal {
.pop_n(list_size)
.ok_or(format!("Expected {} value on the stack", list_size))?;

dbg!(last_list.clone());
let type_annotated_values = last_list
.iter()
.map(|interpreter_result| {
interpreter_result
.get_val()
.ok_or("Failed to get value from the stack".to_string())
.ok_or("Internal Error: Failed to construct tuple".to_string())
})
.collect::<Result<Vec<TypeAnnotatedValue>, String>>()?;

Expand Down Expand Up @@ -634,7 +637,7 @@ mod internal {
.map(|interpreter_result| {
interpreter_result
.get_val()
.ok_or("Failed to get value from the stack".to_string())
.ok_or("Internal Error: Failed to construct resource".to_string())
})
.collect::<Result<Vec<TypeAnnotatedValue>, String>>()?;

Expand Down Expand Up @@ -666,9 +669,9 @@ mod internal {
let type_anntoated_values = last_n_elements
.iter()
.map(|interpreter_result| {
interpreter_result
.get_val()
.ok_or("Failed to get value from the stack".to_string())
interpreter_result.get_val().ok_or(
"Internal Error: Failed to call indexed resource method".to_string(),
)
})
.collect::<Result<Vec<TypeAnnotatedValue>, String>>()?;

Expand All @@ -693,17 +696,17 @@ mod internal {
arg_size,
method,
} => {
let last_n_elements = interpreter
.stack
.pop_n(arg_size)
.ok_or("Failed to get values from the stack".to_string())?;
let last_n_elements = interpreter.stack.pop_n(arg_size).ok_or(
"Internal error: Failed to get arguments for static resource method"
.to_string(),
)?;

let type_anntoated_values = last_n_elements
.iter()
.map(|interpreter_result| {
interpreter_result
.get_val()
.ok_or("Failed to get value from the stack".to_string())
interpreter_result.get_val().ok_or(
"Internal error: Failed to call static resource method".to_string(),
)
})
.collect::<Result<Vec<TypeAnnotatedValue>, String>>()?;

Expand All @@ -724,25 +727,25 @@ mod internal {
.push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string()));
}
FunctionReferenceType::IndexedResourceDrop { resource, arg_size } => {
let last_n_elements = interpreter
.stack
.pop_n(arg_size)
.ok_or("Failed to get values from the stack".to_string())?;
let last_n_elements = interpreter.stack.pop_n(arg_size).ok_or(
"Internal Error: Failed to get resource parameters for indexed resource drop"
.to_string(),
)?;

let type_anntoated_values = last_n_elements
let type_annotated_values = last_n_elements
.iter()
.map(|interpreter_result| {
interpreter_result
.get_val()
.ok_or("Failed to get value from the stack".to_string())
interpreter_result.get_val().ok_or(
"Internal Error: Failed to call indexed resource drop".to_string(),
)
})
.collect::<Result<Vec<TypeAnnotatedValue>, String>>()?;

let parsed_function_name = ParsedFunctionName {
site,
function: ParsedFunctionReference::IndexedResourceDrop {
resource,
resource_params: type_anntoated_values
resource_params: type_annotated_values
.iter()
.map(type_annotated_value_to_string)
.collect::<Result<Vec<String>, String>>()?,
Expand All @@ -758,27 +761,27 @@ mod internal {
Ok(())
}

// Separate variant
pub(crate) async fn run_call_instruction(
argument_size: usize,
arg_size: usize,
interpreter: &mut Interpreter,
) -> Result<(), String> {
let function_name = interpreter
.stack
.pop_str()
.ok_or("Failed to get a function name from the stack".to_string())?;
.ok_or("Internal Error: Failed to get a function name".to_string())?;

let last_n_elements = interpreter
.stack
.pop_n(argument_size)
.ok_or("Failed to get values from the stack".to_string())?;
.pop_n(arg_size)
.ok_or("Internal Error: Failed to get arguments for the function call".to_string())?;

let type_anntoated_values = last_n_elements
.iter()
.map(|interpreter_result| {
interpreter_result
.get_val()
.ok_or("Failed to get value from the stack".to_string())
interpreter_result.get_val().ok_or(format!(
"Internal Error: Failed to call function {}",
function_name
))
})
.collect::<Result<Vec<TypeAnnotatedValue>, String>>()?;

Expand Down Expand Up @@ -921,19 +924,19 @@ mod internal {
) -> Result<(), String> {
let last_n_elements = interpreter_stack
.pop_n(arg_size)
.ok_or("Failed to get values from the stack".to_string())?;
.ok_or("Internal Error: Failed to get arguments for concatenation".to_string())?;

let type_anntoated_values = last_n_elements
let type_annotated_values = last_n_elements
.iter()
.map(|interpreter_result| {
interpreter_result
.get_val()
.ok_or("Failed to get value from the stack".to_string())
.ok_or("Internal Error: Failed to execute concatenation".to_string())
})
.collect::<Result<Vec<TypeAnnotatedValue>, String>>()?;

let mut str = String::new();
for value in type_anntoated_values {
for value in type_annotated_values {
let result = value
.get_literal()
.ok_or("Expected a literal value".to_string())?
Expand Down
Loading

0 comments on commit a424cb9

Please sign in to comment.