mirror of
https://github.com/fluencelabs/wasmer
synced 2025-07-31 23:32:04 +00:00
feat(interface-types) Implement the string.size
instruction.
This commit is contained in:
@@ -219,6 +219,8 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
0x24 => (input, Instruction::StringSize),
|
||||||
|
|
||||||
_ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))),
|
_ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -620,7 +622,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_instructions() {
|
fn test_instructions() {
|
||||||
let input = &[
|
let input = &[
|
||||||
0x24, // list of 36 items
|
0x25, // list of 37 items
|
||||||
0x00, 0x01, // ArgumentGet { index: 1 }
|
0x00, 0x01, // ArgumentGet { index: 1 }
|
||||||
0x01, 0x01, // CallCore { function_index: 1 }
|
0x01, 0x01, // CallCore { function_index: 1 }
|
||||||
0x02, // S8FromI32
|
0x02, // S8FromI32
|
||||||
@@ -657,6 +659,7 @@ mod tests {
|
|||||||
0x21, // I64FromU64
|
0x21, // I64FromU64
|
||||||
0x22, // StringLiftMemory
|
0x22, // StringLiftMemory
|
||||||
0x23, 0x01, // StringLowerMemory { allocator_index: 1 }
|
0x23, 0x01, // StringLowerMemory { allocator_index: 1 }
|
||||||
|
0x24, // StringSize
|
||||||
0x0a,
|
0x0a,
|
||||||
];
|
];
|
||||||
let output = Ok((
|
let output = Ok((
|
||||||
@@ -698,6 +701,7 @@ mod tests {
|
|||||||
Instruction::I64FromU64,
|
Instruction::I64FromU64,
|
||||||
Instruction::StringLiftMemory,
|
Instruction::StringLiftMemory,
|
||||||
Instruction::StringLowerMemory { allocator_index: 1 },
|
Instruction::StringLowerMemory { allocator_index: 1 },
|
||||||
|
Instruction::StringSize,
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@@ -62,6 +62,7 @@ mod keyword {
|
|||||||
custom_keyword!(i64_from_u64 = "i64.from_u64");
|
custom_keyword!(i64_from_u64 = "i64.from_u64");
|
||||||
custom_keyword!(string_lift_memory = "string.lift_memory");
|
custom_keyword!(string_lift_memory = "string.lift_memory");
|
||||||
custom_keyword!(string_lower_memory = "string.lower_memory");
|
custom_keyword!(string_lower_memory = "string.lower_memory");
|
||||||
|
custom_keyword!(string_size = "string.size");
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse<'_> for InterfaceType {
|
impl Parse<'_> for InterfaceType {
|
||||||
@@ -285,6 +286,10 @@ impl<'a> Parse<'a> for Instruction {
|
|||||||
Ok(Instruction::StringLowerMemory {
|
Ok(Instruction::StringLowerMemory {
|
||||||
allocator_index: parser.parse()?,
|
allocator_index: parser.parse()?,
|
||||||
})
|
})
|
||||||
|
} else if lookahead.peek::<keyword::string_size>() {
|
||||||
|
parser.parse::<keyword::string_size>()?;
|
||||||
|
|
||||||
|
Ok(Instruction::StringSize)
|
||||||
} else {
|
} else {
|
||||||
Err(lookahead.error())
|
Err(lookahead.error())
|
||||||
}
|
}
|
||||||
@@ -666,6 +671,7 @@ mod tests {
|
|||||||
"i64.from_u64",
|
"i64.from_u64",
|
||||||
"string.lift_memory",
|
"string.lift_memory",
|
||||||
"string.lower_memory 42",
|
"string.lower_memory 42",
|
||||||
|
"string.size",
|
||||||
];
|
];
|
||||||
let outputs = vec![
|
let outputs = vec![
|
||||||
Instruction::ArgumentGet { index: 7 },
|
Instruction::ArgumentGet { index: 7 },
|
||||||
@@ -706,6 +712,7 @@ mod tests {
|
|||||||
Instruction::StringLowerMemory {
|
Instruction::StringLowerMemory {
|
||||||
allocator_index: 42,
|
allocator_index: 42,
|
||||||
},
|
},
|
||||||
|
Instruction::StringSize,
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(inputs.len(), outputs.len());
|
assert_eq!(inputs.len(), outputs.len());
|
||||||
|
@@ -299,6 +299,8 @@ where
|
|||||||
0x23_u8.to_bytes(writer)?;
|
0x23_u8.to_bytes(writer)?;
|
||||||
(*allocator_index as u64).to_bytes(writer)?;
|
(*allocator_index as u64).to_bytes(writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::StringSize => 0x24_u8.to_bytes(writer)?,
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -577,9 +579,10 @@ mod tests {
|
|||||||
Instruction::I64FromU64,
|
Instruction::I64FromU64,
|
||||||
Instruction::StringLiftMemory,
|
Instruction::StringLiftMemory,
|
||||||
Instruction::StringLowerMemory { allocator_index: 1 },
|
Instruction::StringLowerMemory { allocator_index: 1 },
|
||||||
|
Instruction::StringSize,
|
||||||
],
|
],
|
||||||
&[
|
&[
|
||||||
0x24, // list of 36 items
|
0x25, // list of 37 items
|
||||||
0x00, 0x01, // ArgumentGet { index: 1 }
|
0x00, 0x01, // ArgumentGet { index: 1 }
|
||||||
0x01, 0x01, // CallCore { function_index: 1 }
|
0x01, 0x01, // CallCore { function_index: 1 }
|
||||||
0x02, // S8FromI32
|
0x02, // S8FromI32
|
||||||
@@ -616,6 +619,7 @@ mod tests {
|
|||||||
0x21, // I64FromU64
|
0x21, // I64FromU64
|
||||||
0x22, // StringLiftMemory
|
0x22, // StringLiftMemory
|
||||||
0x23, 0x01, // StringLowerMemory { allocator_index: 1 }
|
0x23, 0x01, // StringLowerMemory { allocator_index: 1 }
|
||||||
|
0x24, // StringSize
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -121,6 +121,7 @@ impl ToString for &Instruction {
|
|||||||
Instruction::StringLowerMemory { allocator_index } => {
|
Instruction::StringLowerMemory { allocator_index } => {
|
||||||
format!(r#"string.lower_memory {}"#, allocator_index)
|
format!(r#"string.lower_memory {}"#, allocator_index)
|
||||||
}
|
}
|
||||||
|
Instruction::StringSize => "string.size".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -391,6 +392,7 @@ mod tests {
|
|||||||
allocator_index: 42,
|
allocator_index: 42,
|
||||||
})
|
})
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|
(&Instruction::StringSize).to_string(),
|
||||||
];
|
];
|
||||||
let outputs = vec![
|
let outputs = vec![
|
||||||
"arg.get 7",
|
"arg.get 7",
|
||||||
@@ -429,6 +431,7 @@ mod tests {
|
|||||||
"i64.from_u64",
|
"i64.from_u64",
|
||||||
"string.lift_memory",
|
"string.lift_memory",
|
||||||
"string.lower_memory 42",
|
"string.lower_memory 42",
|
||||||
|
"string.size",
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(inputs, outputs);
|
assert_eq!(inputs, outputs);
|
||||||
|
@@ -119,4 +119,7 @@ pub enum Instruction {
|
|||||||
/// The allocator function index.
|
/// The allocator function index.
|
||||||
allocator_index: u32,
|
allocator_index: u32,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// The `string.size` instruction.
|
||||||
|
StringSize,
|
||||||
}
|
}
|
||||||
|
@@ -135,6 +135,34 @@ executable_instruction!(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
executable_instruction!(
|
||||||
|
string_size(instruction: Instruction) -> _ {
|
||||||
|
move |runtime| -> _ {
|
||||||
|
let value = runtime.stack.peek1().ok_or_else(|| {
|
||||||
|
InstructionError::new(
|
||||||
|
instruction,
|
||||||
|
InstructionErrorKind::StackIsTooSmall { needed: 1 },
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if let InterfaceValue::String(string) = value {
|
||||||
|
let length = string.len() as i32;
|
||||||
|
runtime.stack.push(InterfaceValue::I32(length));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::new(
|
||||||
|
instruction,
|
||||||
|
InstructionErrorKind::InvalidValueOnTheStack {
|
||||||
|
expected_type: InterfaceType::String,
|
||||||
|
received_type: value.into(),
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
test_executable_instruction!(
|
test_executable_instruction!(
|
||||||
@@ -323,4 +351,36 @@ mod tests {
|
|||||||
},
|
},
|
||||||
error: r#"`string.lower_memory 153` the local or import function `153` has the signature `[I32] -> [I32]` but it received values of kind `[I32, I32] -> []`"#,
|
error: r#"`string.lower_memory 153` the local or import function `153` has the signature `[I32] -> [I32]` but it received values of kind `[I32, I32] -> []`"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test_executable_instruction!(
|
||||||
|
test_string_size =
|
||||||
|
instructions: [
|
||||||
|
Instruction::ArgumentGet { index: 0 },
|
||||||
|
Instruction::StringSize,
|
||||||
|
],
|
||||||
|
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
|
||||||
|
instance: Instance::new(),
|
||||||
|
stack: [InterfaceValue::String("Hello, World!".into()), InterfaceValue::I32(13)],
|
||||||
|
);
|
||||||
|
|
||||||
|
test_executable_instruction!(
|
||||||
|
test_string_size__stack_is_too_small =
|
||||||
|
instructions: [
|
||||||
|
Instruction::StringSize,
|
||||||
|
],
|
||||||
|
invocation_inputs: [],
|
||||||
|
instance: Instance::new(),
|
||||||
|
error: r#"`string.size` needed to read `1` value(s) from the stack, but it doesn't contain enough data"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
test_executable_instruction!(
|
||||||
|
test_string_size__invalid_value_on_the_stack =
|
||||||
|
instructions: [
|
||||||
|
Instruction::ArgumentGet { index: 0 },
|
||||||
|
Instruction::StringSize,
|
||||||
|
],
|
||||||
|
invocation_inputs: [InterfaceValue::I32(42)],
|
||||||
|
instance: Instance::new(),
|
||||||
|
error: r#"`string.size` read a value of type `I32` from the stack, but the type `String` was expected"#,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@@ -234,6 +234,7 @@ where
|
|||||||
Instruction::StringLowerMemory { allocator_index } => {
|
Instruction::StringLowerMemory { allocator_index } => {
|
||||||
instructions::string_lower_memory(*allocator_index, *instruction)
|
instructions::string_lower_memory(*allocator_index, *instruction)
|
||||||
}
|
}
|
||||||
|
Instruction::StringSize => instructions::string_size(*instruction),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user