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,
|
Class as AbcClass, Instance as AbcInstance, Method as AbcMethod, MethodBody as AbcMethodBody,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::method::ParamConfig;
|
|
||||||
use super::string::AvmString;
|
use super::string::AvmString;
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
@ -338,11 +337,10 @@ impl<'gc> Class<'gc> {
|
||||||
let method = Method::from_builtin_and_params(
|
let method = Method::from_builtin_and_params(
|
||||||
table_native_call_handler,
|
table_native_call_handler,
|
||||||
name,
|
name,
|
||||||
vec![ParamConfig::of_type(
|
// A 'callable' class doesn't have a signature - let the
|
||||||
"val",
|
// method do any needed coercions
|
||||||
Multiname::any(activation.context.gc_context),
|
vec![],
|
||||||
)],
|
true,
|
||||||
false,
|
|
||||||
activation.context.gc_context,
|
activation.context.gc_context,
|
||||||
);
|
);
|
||||||
native_call_handler = Some(method);
|
native_call_handler = Some(method);
|
||||||
|
|
|
@ -32,7 +32,7 @@ mod namespace;
|
||||||
mod number;
|
mod number;
|
||||||
mod object;
|
mod object;
|
||||||
mod qname;
|
mod qname;
|
||||||
mod regexp;
|
mod reg_exp;
|
||||||
mod string;
|
mod string;
|
||||||
mod toplevel;
|
mod toplevel;
|
||||||
mod r#uint;
|
mod r#uint;
|
||||||
|
@ -523,7 +523,6 @@ pub fn load_player_globals<'gc>(
|
||||||
)?;
|
)?;
|
||||||
function(activation, "", "unescape", toplevel::unescape, script)?;
|
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!(vector, activation, vector::create_class(activation), script);
|
||||||
|
|
||||||
avm2_system_class!(date, activation, date::create_class(activation), script);
|
avm2_system_class!(date, activation, date::create_class(activation), script);
|
||||||
|
@ -604,6 +603,7 @@ fn load_playerglobal<'gc>(
|
||||||
("", "Error", error),
|
("", "Error", error),
|
||||||
("", "ArgumentError", argumenterror),
|
("", "ArgumentError", argumenterror),
|
||||||
("", "RangeError", rangeerror),
|
("", "RangeError", rangeerror),
|
||||||
|
("", "RegExp", regexp),
|
||||||
("", "ReferenceError", referenceerror),
|
("", "ReferenceError", referenceerror),
|
||||||
("", "TypeError", typeerror),
|
("", "TypeError", typeerror),
|
||||||
("", "VerifyError", verifyerror),
|
("", "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 "Math.as"
|
||||||
include "RangeError.as"
|
include "RangeError.as"
|
||||||
include "ReferenceError.as"
|
include "ReferenceError.as"
|
||||||
|
include "RegExp.as"
|
||||||
include "SecurityError.as"
|
include "SecurityError.as"
|
||||||
include "SyntaxError.as"
|
include "SyntaxError.as"
|
||||||
include "URIError.as"
|
include "URIError.as"
|
||||||
|
|
|
@ -1,32 +1,22 @@
|
||||||
//! `RegExp` impl
|
//! `RegExp` impl
|
||||||
|
|
||||||
use crate::avm2::class::Class;
|
|
||||||
use crate::avm2::error::type_error;
|
use crate::avm2::error::type_error;
|
||||||
use crate::avm2::method::{Method, NativeMethodImpl, ParamConfig};
|
use crate::avm2::object::{ArrayObject, Object, TObject};
|
||||||
use crate::avm2::object::{regexp_allocator, ArrayObject, FunctionObject, Object, TObject};
|
|
||||||
use crate::avm2::regexp::RegExpFlags;
|
use crate::avm2::regexp::RegExpFlags;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use crate::avm2::Multiname;
|
|
||||||
use crate::avm2::QName;
|
|
||||||
use crate::avm2::{activation::Activation, array::ArrayStorage};
|
use crate::avm2::{activation::Activation, array::ArrayStorage};
|
||||||
use crate::string::{AvmString, WString};
|
use crate::string::{AvmString, WString};
|
||||||
use gc_arena::GcCell;
|
|
||||||
|
|
||||||
// All of these methods will be defined as both
|
pub use crate::avm2::object::reg_exp_allocator;
|
||||||
// AS3 instance methods and methods on the `Array` class prototype.
|
|
||||||
const PUBLIC_INSTANCE_AND_PROTO_METHODS: &[(&str, NativeMethodImpl)] =
|
|
||||||
&[("exec", exec), ("test", test)];
|
|
||||||
|
|
||||||
/// Implements `RegExp`'s instance initializer.
|
/// Implements `RegExp`'s `init` method, which is called from the constructor
|
||||||
pub fn instance_init<'gc>(
|
pub fn init<'gc>(
|
||||||
activation: &mut Activation<'_, 'gc>,
|
activation: &mut Activation<'_, 'gc>,
|
||||||
this: Option<Object<'gc>>,
|
this: Option<Object<'gc>>,
|
||||||
args: &[Value<'gc>],
|
args: &[Value<'gc>],
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
if let Some(this) = this {
|
if let Some(this) = this {
|
||||||
activation.super_init(this, &[])?;
|
|
||||||
|
|
||||||
if let Some(mut regexp) = this.as_regexp_mut(activation.context.gc_context) {
|
if let Some(mut regexp) = this.as_regexp_mut(activation.context.gc_context) {
|
||||||
let source: AvmString<'gc> = match args.get(0) {
|
let source: AvmString<'gc> = match args.get(0) {
|
||||||
Some(Value::Undefined) => "".into(),
|
Some(Value::Undefined) => "".into(),
|
||||||
|
@ -76,7 +66,7 @@ pub fn instance_init<'gc>(
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn class_call<'gc>(
|
pub fn call_handler<'gc>(
|
||||||
activation: &mut Activation<'_, 'gc>,
|
activation: &mut Activation<'_, 'gc>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
args: &[Value<'gc>],
|
args: &[Value<'gc>],
|
||||||
|
@ -92,39 +82,8 @@ fn class_call<'gc>(
|
||||||
return this_class.construct(activation, args).map(|o| o.into());
|
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`
|
/// Implements `RegExp.dotall`
|
||||||
pub fn dotall<'gc>(
|
pub fn get_dotall<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc>,
|
_activation: &mut Activation<'_, 'gc>,
|
||||||
this: Option<Object<'gc>>,
|
this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -139,7 +98,7 @@ pub fn dotall<'gc>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements `RegExp.extended`
|
/// Implements `RegExp.extended`
|
||||||
pub fn extended<'gc>(
|
pub fn get_extended<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc>,
|
_activation: &mut Activation<'_, 'gc>,
|
||||||
this: Option<Object<'gc>>,
|
this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -154,7 +113,7 @@ pub fn extended<'gc>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements `RegExp.global`
|
/// Implements `RegExp.global`
|
||||||
pub fn global<'gc>(
|
pub fn get_global<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc>,
|
_activation: &mut Activation<'_, 'gc>,
|
||||||
this: Option<Object<'gc>>,
|
this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -169,7 +128,7 @@ pub fn global<'gc>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements `RegExp.ignoreCase`
|
/// Implements `RegExp.ignoreCase`
|
||||||
pub fn ignore_case<'gc>(
|
pub fn get_ignore_case<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc>,
|
_activation: &mut Activation<'_, 'gc>,
|
||||||
this: Option<Object<'gc>>,
|
this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -184,7 +143,7 @@ pub fn ignore_case<'gc>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements `RegExp.multiline`
|
/// Implements `RegExp.multiline`
|
||||||
pub fn multiline<'gc>(
|
pub fn get_multiline<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc>,
|
_activation: &mut Activation<'_, 'gc>,
|
||||||
this: Option<Object<'gc>>,
|
this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -199,7 +158,7 @@ pub fn multiline<'gc>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements `RegExp.lastIndex`'s getter
|
/// Implements `RegExp.lastIndex`'s getter
|
||||||
pub fn last_index<'gc>(
|
pub fn get_last_index<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc>,
|
_activation: &mut Activation<'_, 'gc>,
|
||||||
this: Option<Object<'gc>>,
|
this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -233,7 +192,7 @@ pub fn set_last_index<'gc>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements `RegExp.source`
|
/// Implements `RegExp.source`
|
||||||
pub fn source<'gc>(
|
pub fn get_source<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc>,
|
_activation: &mut Activation<'_, 'gc>,
|
||||||
this: Option<Object<'gc>>,
|
this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -307,59 +266,3 @@ pub fn test<'gc>(
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
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::program_3d_object::Program3DObject;
|
||||||
pub use crate::avm2::object::proxy_object::{proxy_allocator, ProxyObject};
|
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::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::script_object::{ScriptObject, ScriptObjectData};
|
||||||
pub use crate::avm2::object::sound_object::{sound_allocator, QueuedPlay, SoundData, SoundObject};
|
pub use crate::avm2::object::sound_object::{sound_allocator, QueuedPlay, SoundData, SoundObject};
|
||||||
pub use crate::avm2::object::soundchannel_object::{sound_channel_allocator, SoundChannelObject};
|
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};
|
use std::cell::{Ref, RefMut};
|
||||||
|
|
||||||
/// A class instance allocator that allocates RegExp objects.
|
/// A class instance allocator that allocates RegExp objects.
|
||||||
pub fn regexp_allocator<'gc>(
|
pub fn reg_exp_allocator<'gc>(
|
||||||
class: ClassObject<'gc>,
|
class: ClassObject<'gc>,
|
||||||
activation: &mut Activation<'_, 'gc>,
|
activation: &mut Activation<'_, 'gc>,
|
||||||
) -> Result<Object<'gc>, Error<'gc>> {
|
) -> Result<Object<'gc>, Error<'gc>> {
|
||||||
|
|
Loading…
Reference in New Issue