avm2: Convert RegExp to ActionScript
This commit is contained in:
parent
6fda813f0c
commit
27092ecb76
|
@ -19,7 +19,6 @@ use swf::avm2::types::{
|
|||
Class as AbcClass, Instance as AbcInstance, Method as AbcMethod, MethodBody as AbcMethodBody,
|
||||
};
|
||||
|
||||
use super::method::ParamConfig;
|
||||
use super::string::AvmString;
|
||||
|
||||
bitflags! {
|
||||
|
@ -338,11 +337,10 @@ impl<'gc> Class<'gc> {
|
|||
let method = Method::from_builtin_and_params(
|
||||
table_native_call_handler,
|
||||
name,
|
||||
vec![ParamConfig::of_type(
|
||||
"val",
|
||||
Multiname::any(activation.context.gc_context),
|
||||
)],
|
||||
false,
|
||||
// A 'callable' class doesn't have a signature - let the
|
||||
// method do any needed coercions
|
||||
vec![],
|
||||
true,
|
||||
activation.context.gc_context,
|
||||
);
|
||||
native_call_handler = Some(method);
|
||||
|
|
|
@ -32,7 +32,7 @@ mod namespace;
|
|||
mod number;
|
||||
mod object;
|
||||
mod qname;
|
||||
mod regexp;
|
||||
mod reg_exp;
|
||||
mod string;
|
||||
mod toplevel;
|
||||
mod r#uint;
|
||||
|
@ -523,7 +523,6 @@ pub fn load_player_globals<'gc>(
|
|||
)?;
|
||||
function(activation, "", "unescape", toplevel::unescape, script)?;
|
||||
|
||||
avm2_system_class!(regexp, activation, regexp::create_class(activation), script);
|
||||
avm2_system_class!(vector, activation, vector::create_class(activation), script);
|
||||
|
||||
avm2_system_class!(date, activation, date::create_class(activation), script);
|
||||
|
@ -604,6 +603,7 @@ fn load_playerglobal<'gc>(
|
|||
("", "Error", error),
|
||||
("", "ArgumentError", argumenterror),
|
||||
("", "RangeError", rangeerror),
|
||||
("", "RegExp", regexp),
|
||||
("", "ReferenceError", referenceerror),
|
||||
("", "TypeError", typeerror),
|
||||
("", "VerifyError", verifyerror),
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package {
|
||||
[Ruffle(InstanceAllocator)]
|
||||
[Ruffle(CallHandler)]
|
||||
public dynamic class RegExp {
|
||||
public function RegExp(re:* = undefined, flags:* = undefined) {
|
||||
this.init(re, flags)
|
||||
}
|
||||
|
||||
private native function init(re:*, flags:*):void;
|
||||
|
||||
public native function get dotall():Boolean;
|
||||
public native function get extended():Boolean;
|
||||
public native function get global():Boolean;
|
||||
public native function get ignoreCase():Boolean;
|
||||
public native function get multiline():Boolean;
|
||||
public native function get lastIndex():int;
|
||||
public native function set lastIndex(value:int):void;
|
||||
public native function get source():String;
|
||||
|
||||
AS3 native function exec(str:String = ""):Object;
|
||||
AS3 native function test(str:String = ""):Boolean;
|
||||
|
||||
prototype.exec = function(str:String = ""):Object {
|
||||
return this.AS3::exec(str);
|
||||
}
|
||||
|
||||
prototype.test = function(str:String = ""):Boolean {
|
||||
return this.AS3::test(str);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ include "TypeError.as"
|
|||
include "Math.as"
|
||||
include "RangeError.as"
|
||||
include "ReferenceError.as"
|
||||
include "RegExp.as"
|
||||
include "SecurityError.as"
|
||||
include "SyntaxError.as"
|
||||
include "URIError.as"
|
||||
|
|
|
@ -1,32 +1,22 @@
|
|||
//! `RegExp` impl
|
||||
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::error::type_error;
|
||||
use crate::avm2::method::{Method, NativeMethodImpl, ParamConfig};
|
||||
use crate::avm2::object::{regexp_allocator, ArrayObject, FunctionObject, Object, TObject};
|
||||
use crate::avm2::object::{ArrayObject, Object, TObject};
|
||||
use crate::avm2::regexp::RegExpFlags;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use crate::avm2::Multiname;
|
||||
use crate::avm2::QName;
|
||||
use crate::avm2::{activation::Activation, array::ArrayStorage};
|
||||
use crate::string::{AvmString, WString};
|
||||
use gc_arena::GcCell;
|
||||
|
||||
// All of these methods will be defined as both
|
||||
// AS3 instance methods and methods on the `Array` class prototype.
|
||||
const PUBLIC_INSTANCE_AND_PROTO_METHODS: &[(&str, NativeMethodImpl)] =
|
||||
&[("exec", exec), ("test", test)];
|
||||
pub use crate::avm2::object::reg_exp_allocator;
|
||||
|
||||
/// Implements `RegExp`'s instance initializer.
|
||||
pub fn instance_init<'gc>(
|
||||
/// Implements `RegExp`'s `init` method, which is called from the constructor
|
||||
pub fn init<'gc>(
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
this: Option<Object<'gc>>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Some(this) = this {
|
||||
activation.super_init(this, &[])?;
|
||||
|
||||
if let Some(mut regexp) = this.as_regexp_mut(activation.context.gc_context) {
|
||||
let source: AvmString<'gc> = match args.get(0) {
|
||||
Some(Value::Undefined) => "".into(),
|
||||
|
@ -76,7 +66,7 @@ pub fn instance_init<'gc>(
|
|||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
fn class_call<'gc>(
|
||||
pub fn call_handler<'gc>(
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
_this: Option<Object<'gc>>,
|
||||
args: &[Value<'gc>],
|
||||
|
@ -92,39 +82,8 @@ fn class_call<'gc>(
|
|||
return this_class.construct(activation, args).map(|o| o.into());
|
||||
}
|
||||
|
||||
/// Implements `RegExp`'s class initializer.
|
||||
pub fn class_init<'gc>(
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Some(this) = this {
|
||||
let scope = activation.create_scopechain();
|
||||
let gc_context = activation.context.gc_context;
|
||||
let this_class = this.as_class_object().unwrap();
|
||||
let regexp_proto = this_class.prototype();
|
||||
|
||||
for (name, method) in PUBLIC_INSTANCE_AND_PROTO_METHODS {
|
||||
regexp_proto.set_string_property_local(
|
||||
*name,
|
||||
FunctionObject::from_method(
|
||||
activation,
|
||||
Method::from_builtin(*method, name, gc_context),
|
||||
scope,
|
||||
None,
|
||||
Some(this_class),
|
||||
)
|
||||
.into(),
|
||||
activation,
|
||||
)?;
|
||||
regexp_proto.set_local_property_is_enumerable(gc_context, (*name).into(), false);
|
||||
}
|
||||
}
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Implements `RegExp.dotall`
|
||||
pub fn dotall<'gc>(
|
||||
pub fn get_dotall<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc>,
|
||||
this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -139,7 +98,7 @@ pub fn dotall<'gc>(
|
|||
}
|
||||
|
||||
/// Implements `RegExp.extended`
|
||||
pub fn extended<'gc>(
|
||||
pub fn get_extended<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc>,
|
||||
this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -154,7 +113,7 @@ pub fn extended<'gc>(
|
|||
}
|
||||
|
||||
/// Implements `RegExp.global`
|
||||
pub fn global<'gc>(
|
||||
pub fn get_global<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc>,
|
||||
this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -169,7 +128,7 @@ pub fn global<'gc>(
|
|||
}
|
||||
|
||||
/// Implements `RegExp.ignoreCase`
|
||||
pub fn ignore_case<'gc>(
|
||||
pub fn get_ignore_case<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc>,
|
||||
this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -184,7 +143,7 @@ pub fn ignore_case<'gc>(
|
|||
}
|
||||
|
||||
/// Implements `RegExp.multiline`
|
||||
pub fn multiline<'gc>(
|
||||
pub fn get_multiline<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc>,
|
||||
this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -199,7 +158,7 @@ pub fn multiline<'gc>(
|
|||
}
|
||||
|
||||
/// Implements `RegExp.lastIndex`'s getter
|
||||
pub fn last_index<'gc>(
|
||||
pub fn get_last_index<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc>,
|
||||
this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -233,7 +192,7 @@ pub fn set_last_index<'gc>(
|
|||
}
|
||||
|
||||
/// Implements `RegExp.source`
|
||||
pub fn source<'gc>(
|
||||
pub fn get_source<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc>,
|
||||
this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -307,59 +266,3 @@ pub fn test<'gc>(
|
|||
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `RegExp`'s class.
|
||||
pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> GcCell<'gc, Class<'gc>> {
|
||||
let mc = activation.context.gc_context;
|
||||
let class = Class::new(
|
||||
QName::new(activation.avm2().public_namespace, "RegExp"),
|
||||
Some(Multiname::new(activation.avm2().public_namespace, "Object")),
|
||||
Method::from_builtin_and_params(
|
||||
instance_init,
|
||||
"<RegExp instance initializer>",
|
||||
vec![
|
||||
ParamConfig::optional("re", Multiname::any(mc), Value::Undefined),
|
||||
ParamConfig::optional("flags", Multiname::any(mc), Value::Undefined),
|
||||
],
|
||||
false,
|
||||
mc,
|
||||
),
|
||||
Method::from_builtin(class_init, "<RegExp class initializer>", mc),
|
||||
mc,
|
||||
);
|
||||
|
||||
let mut write = class.write(mc);
|
||||
write.set_instance_allocator(regexp_allocator);
|
||||
write.set_call_handler(Method::from_builtin(
|
||||
class_call,
|
||||
"<RegExp call handler>",
|
||||
mc,
|
||||
));
|
||||
|
||||
const PUBLIC_INSTANCE_PROPERTIES: &[(
|
||||
&str,
|
||||
Option<NativeMethodImpl>,
|
||||
Option<NativeMethodImpl>,
|
||||
)] = &[
|
||||
("dotall", Some(dotall), None),
|
||||
("extended", Some(extended), None),
|
||||
("global", Some(global), None),
|
||||
("ignoreCase", Some(ignore_case), None),
|
||||
("multiline", Some(multiline), None),
|
||||
("lastIndex", Some(last_index), Some(set_last_index)),
|
||||
("source", Some(source), None),
|
||||
];
|
||||
write.define_builtin_instance_properties(
|
||||
mc,
|
||||
activation.avm2().public_namespace,
|
||||
PUBLIC_INSTANCE_PROPERTIES,
|
||||
);
|
||||
|
||||
write.define_builtin_instance_methods(
|
||||
mc,
|
||||
activation.avm2().as3_namespace,
|
||||
PUBLIC_INSTANCE_AND_PROTO_METHODS,
|
||||
);
|
||||
|
||||
class
|
||||
}
|
|
@ -84,7 +84,7 @@ pub use crate::avm2::object::primitive_object::{primitive_allocator, PrimitiveOb
|
|||
pub use crate::avm2::object::program_3d_object::Program3DObject;
|
||||
pub use crate::avm2::object::proxy_object::{proxy_allocator, ProxyObject};
|
||||
pub use crate::avm2::object::qname_object::{qname_allocator, QNameObject};
|
||||
pub use crate::avm2::object::regexp_object::{regexp_allocator, RegExpObject};
|
||||
pub use crate::avm2::object::regexp_object::{reg_exp_allocator, RegExpObject};
|
||||
pub use crate::avm2::object::script_object::{ScriptObject, ScriptObjectData};
|
||||
pub use crate::avm2::object::sound_object::{sound_allocator, QueuedPlay, SoundData, SoundObject};
|
||||
pub use crate::avm2::object::soundchannel_object::{sound_channel_allocator, SoundChannelObject};
|
||||
|
|
|
@ -12,7 +12,7 @@ use gc_arena::{Collect, GcCell, MutationContext};
|
|||
use std::cell::{Ref, RefMut};
|
||||
|
||||
/// A class instance allocator that allocates RegExp objects.
|
||||
pub fn regexp_allocator<'gc>(
|
||||
pub fn reg_exp_allocator<'gc>(
|
||||
class: ClassObject<'gc>,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
) -> Result<Object<'gc>, Error<'gc>> {
|
||||
|
|
Loading…
Reference in New Issue