Commit 84ed0ebe authored by Jeff Smits's avatar Jeff Smits

WIP, i.e. currently broken: First step towards more efficient lookup of names

parent dc2955d6
......@@ -156,6 +156,17 @@ fn gen_primitives() {
"preserve_annotations_attachments",
// STACKTRACE
"stacktrace_get_all_frame_names",
// Overrides
"SRTS_EXT_at_end_1_0",
"SRTS_EXT_concat_0_0",
"SRTS_EXT_crush_3_0",
"SRTS_EXT_eq_ignore_annos_0_1",
"SRTS_EXT_fatal_err_0_3",
"SRTS_EXT_filter_1_0",
"SRTS_EXT_flatten_list_0_0",
"SRTS_EXT_newint_0_0",
"SRTS_EXT_repeat_1_0",
"SRTS_EXT_string_replace_0_2",
];
// let jsglr = [];
......
......@@ -148,7 +148,11 @@ impl<'a, 's> From<&'a Option<InternedString<'s>>> for Value<'s> {
#[derive(Debug, Clone, PartialEq, Eq)]
struct Scope<'s> {
strategy: FnvHashMap<InternedString<'s>, (::std::result::Result<FnvHashSet<InternedString<'s>>, DynamicCall>, usize)>,
strategy: FnvHashMap<
InternedString<'s>,
(::std::result::Result<FnvHashSet<InternedString<'s>>, DynamicCall>,
usize),
>,
term: FnvHashMap<InternedString<'s>, Value<'s>>,
is_overlay: bool,
is_unbound_overlay: bool,
......@@ -156,19 +160,18 @@ struct Scope<'s> {
impl<'s> Scope<'s> {
fn from_args<I1, I2>(no_of_scopes: usize, sargs: I1, targs: I2) -> Self
where
I1: IntoIterator<Item = InternedString<'s>>,
I2: IntoIterator<Item = InternedString<'s>>,
where
I1: IntoIterator<Item = InternedString<'s>>,
I2: IntoIterator<Item = InternedString<'s>>,
{
Scope {
term: targs
.into_iter()
.map(|targ| (targ, Value::UnBound))
.collect(),
strategy: sargs.into_iter()
.map(|sarg| {
(sarg, (Ok(FnvHashSet::default()), no_of_scopes))
})
strategy: sargs
.into_iter()
.map(|sarg| (sarg, (Ok(FnvHashSet::default()), no_of_scopes)))
.collect(),
is_overlay: false,
is_unbound_overlay: false,
......@@ -284,7 +287,13 @@ impl<'s> Scopes<'s> {
let vars = vars.unwrap();
for var in vars {
let mut offset = None;
for (n, scope) in self.0.iter().enumerate().rev().skip(self.0.len() - no_of_scopes).clone() {
for (n, scope) in self.0
.iter()
.enumerate()
.rev()
.skip(self.0.len() - no_of_scopes)
.clone()
{
if offset == None && scope.is_overlay {
offset = Some(n);
}
......@@ -322,19 +331,11 @@ impl<'s> CTreeOptimize for ir_v1_ext::Module<'s> {
Module(name, decls) => {
Module(
name,
decls
.into_iter()
.map(|d| d.optimize(&mut ()))
.collect(),
decls.into_iter().map(|d| d.optimize(&mut ())).collect(),
)
}
Specification(decls) => {
Specification(
decls
.into_iter()
.map(|d| d.optimize(&mut ()))
.collect(),
)
Specification(decls.into_iter().map(|d| d.optimize(&mut ())).collect())
}
}
}
......@@ -350,13 +351,7 @@ impl<'s> CTreeOptimize for ir_v1_ext::Decl<'s> {
match self {
Imports(import_names) => Imports(import_names),
Strategies(defs) => {
Strategies(
defs.into_iter()
.map(|d| d.optimize(&mut ()))
.collect(),
)
}
Strategies(defs) => Strategies(defs.into_iter().map(|d| d.optimize(&mut ())).collect()),
Signature(sdecls) => Signature(sdecls),
}
}
......@@ -372,11 +367,29 @@ impl<'s> CTreeOptimize for ir_v1_ext::Def<'s> {
match self {
SDefT(name, sargs, targs, strat) => {
let mut context = (None, Scopes(vec![Scope::from_args(0, sargs.iter().map(|vd| vd.0), targs.iter().map(|vd| vd.0))]));
let mut context = (
None,
Scopes(vec![
Scope::from_args(
0,
sargs.iter().map(|vd| vd.0),
targs.iter().map(|vd| vd.0)
),
]),
);
SDefT(name, sargs, targs, strat.optimize(&mut context))
}
ExtSDefInl(name, sargs, targs, strat) => {
let mut context = (None, Scopes(vec![Scope::from_args(0, sargs.iter().map(|vd| vd.0), targs.iter().map(|vd| vd.0))]));
let mut context = (
None,
Scopes(vec![
Scope::from_args(
0,
sargs.iter().map(|vd| vd.0),
targs.iter().map(|vd| vd.0)
),
]),
);
ExtSDefInl(name, sargs, targs, strat.optimize(&mut context))
}
ExtSDef(name, sargs, targs) => ExtSDef(name, sargs, targs),
......@@ -396,8 +409,12 @@ impl<'s> CTreeOptimize for ir_v1::Def<'s> {
// TODO: reevaluate this from_args call.
// It gives an empty set of influenced variable to the sargs, which probably not correct at
// this point. The closure given as sarg to this strategy could be made before this one,
// which would make it able to change variables that this Def would be able to observe.
c.1.push_scope(Scope::from_args(no_of_scopes, self.sargs.iter().map(|&s| s), self.targs.iter().map(|&s| s)));
// which would make it able to change variables that this Def would be able to observe.
c.1.push_scope(Scope::from_args(
no_of_scopes,
self.sargs.iter().map(|&s| s),
self.targs.iter().map(|&s| s),
));
self.body = self.body.optimize(c);
c.1.pop_scope();
......@@ -421,7 +438,7 @@ fn conservative_maybe_bind<'s>(scopes: &mut Scopes<'s>) {
fn conservative_maybe_bind2<'s, I>(scopes: &mut Scopes<'s>, affected_names: I)
where
I: IntoIterator<Item=InternedString<'s>>,
I: IntoIterator<Item = InternedString<'s>>,
{
for name in affected_names {
if scopes.get_term(name) == Some(Value::UnBound) {
......@@ -489,7 +506,10 @@ impl<'s> CTreeOptimize for ir_v1::Strategy<'s> {
c.1.apply_strategy(name);
// All affected `UnBound` names will now have the conservative MaybeBound
// since we don't know if and when the sargs are called
conservative_maybe_bind2(&mut c.1, affected_names.into_iter().flat_map(|s| s));
conservative_maybe_bind2(
&mut c.1,
affected_names.into_iter().flat_map(|s| s),
);
}
}
// We also don't know the return value of the call
......@@ -558,7 +578,9 @@ impl<'s> CTreeOptimize for ir_v1::Strategy<'s> {
}
Strategy::Scope(mut names, body) => {
// eprintln!("CTreeOptimize::optimize(Strategy::Scope, _)");
c.1.push_scope(Scope::from_fresh_variables(names.iter().map(|&s| s)));
c.1.push_scope(
Scope::from_fresh_variables(names.iter().map(|&s| s)),
);
let new_body = body.optimize(&mut c);
......@@ -849,7 +871,7 @@ fn match_vars_in_strategy<'s>(
Strategy::CallT(_, ref sargs, _) => {
let result = sargs.iter().map(match_vars_in_strategy).collect::<::std::result::Result<Vec<FnvHashSet<InternedString<'s>>>, DynamicCall>>()?;
Ok(result.into_iter().flat_map(|s| s).collect())
},
}
Strategy::CallDynamic(_, _, _) => Err(DynamicCall),
Strategy::Fail => Ok(FnvHashSet::default()),
Strategy::Id => Ok(FnvHashSet::default()),
......@@ -868,7 +890,7 @@ fn match_vars_in_strategy<'s>(
Strategy::Seq(ref strats) => {
let result = strats.iter().map(match_vars_in_strategy).collect::<::std::result::Result<Vec<FnvHashSet<InternedString<'s>>>, DynamicCall>>()?;
Ok(result.into_iter().flat_map(|s| s).collect())
},
}
Strategy::GuardedLChoice(ref pairs, ref s_else) => {
let pairs_names = pairs
.iter()
......@@ -878,17 +900,23 @@ fn match_vars_in_strategy<'s>(
Ok(one.union(&two).map(|&s| s).collect::<FnvHashSet<InternedString<'s>>>())
})
.collect::<::std::result::Result<Vec<FnvHashSet<InternedString<'s>>>, DynamicCall>>()?;
let pairs_names: FnvHashSet<InternedString<'s>> = pairs_names.into_iter().flat_map(|s| s).collect();
Ok(pairs_names.union(&match_vars_in_strategy(s_else)?).map(|&s| s).collect())
let pairs_names: FnvHashSet<InternedString<'s>> =
pairs_names.into_iter().flat_map(|s| s).collect();
Ok(
pairs_names
.union(&match_vars_in_strategy(s_else)?)
.map(|&s| s)
.collect(),
)
}
Strategy::ConsMatch(ref map, _) => {
let result = map.values().map(match_vars_in_strategy).collect::<::std::result::Result<Vec<FnvHashSet<InternedString<'s>>>, DynamicCall>>()?;
Ok(result.into_iter().flat_map(|s| s).collect())
},
}
Strategy::PrimT(_, ref sargs, _) => {
let result = sargs.iter().map(match_vars_in_strategy).collect::<::std::result::Result<Vec<FnvHashSet<InternedString<'s>>>, DynamicCall>>()?;
Ok(result.into_iter().flat_map(|s| s).collect())
},
}
Strategy::Some(ref s) => match_vars_in_strategy(s),
Strategy::One(ref s) => match_vars_in_strategy(s),
Strategy::All(ref s) => match_vars_in_strategy(s),
......
This diff is collapsed.
......@@ -136,6 +136,7 @@ impl<'s> TryInto<Rc<RefCell<IndexedSet<'s>>>> for Blob<'s> {
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum TermList<'s> {
// TODO: allow annotations on list tail
Cons(ATermRef<'s>, Rc<TermList<'s>>),
Nil,
}
......@@ -154,6 +155,13 @@ impl<'s> TermList<'s> {
TermList::Cons(item, Rc::new(list))
})
}
pub fn with_tail(&self, tail: Rc<Self>) -> Rc<Self> {
match *self {
TermList::Nil => tail,
TermList::Cons(ref h, ref t) => Rc::new(TermList::Cons(h.clone(), t.with_tail(tail)))
}
}
}
impl<'s> IntoIterator for TermList<'s> {
......@@ -334,6 +342,14 @@ impl<'s> ATerm<'s> {
}
}
pub fn get_term_list(&self) -> Option<Rc<TermList<'s>>> {
use self::Term::*;
match self.term {
List(ref tl) => Some(tl.clone()),
_ => None,
}
}
pub fn get_attachments(&self) -> Vec<Attachment> {
RefCell::borrow(&self.attachments).clone()
}
......
This diff is collapsed.
......@@ -9,6 +9,8 @@ use error::Result;
use factory::{ATermFactory, ATermRef};
use primitives;
use primitives::Primitives;
use preprocess::ir_v1::Def;
use overrides;
pub fn read_input<P: AsRef<Path>>(path: &P) -> io::Result<String> {
let mut ctree = String::new();
......@@ -31,11 +33,12 @@ pub fn read_lib<'f>(
f: &'f ATermFactory,
str_path: &Path,
path: &str,
) -> Result<(ATermRef<'f>, Option<&'static Primitives>)> {
) -> Result<(ATermRef<'f>, Option<&'static Primitives>, Option<Vec<Def<'f>>>)> {
let defs = overrides::get(path, f);
if let Some(&(path, prim)) = primitives::LIBS.get(path) {
Ok((read_aterm(f, &Path::new(&str_path).join(path))?, prim))
Ok((read_aterm(f, &Path::new(&str_path).join(path))?, prim, defs))
} else {
Ok((read_aterm(f, &Path::new(path))?, None))
Ok((read_aterm(f, &Path::new(path))?, None, defs))
}
}
......
......@@ -13,6 +13,7 @@ pub mod interpreter;
mod preprocess;
mod context;
mod primitives;
mod overrides;
pub use preprocess::ctree;
pub use preprocess::ir_v1;
pub use preprocess::ir_v2;
......@@ -28,6 +28,7 @@ mod interpreter;
mod preprocess;
mod context;
mod primitives;
mod overrides;
use preprocess::ctree;
......
use factory::ATermFactory;
use preprocess::ir_v1::{Def, Strategy, BuildTerm};
const SRTS_EXT_NAMES: [(&'static str, usize, usize); 10] = [
("SRTS_EXT_at_end_1_0", 1, 0),
("SRTS_EXT_concat_0_0", 0, 0),
("SRTS_EXT_crush_3_0", 3, 0),
("SRTS_EXT_eq_ignore_annos_0_1", 0, 1),
("SRTS_EXT_fatal_err_0_3", 0, 3),
("SRTS_EXT_filter_1_0", 1, 0),
("SRTS_EXT_flatten_list_0_0", 0, 0),
("SRTS_EXT_newint_0_0", 0, 0),
("SRTS_EXT_repeat_1_0", 1, 0),
("SRTS_EXT_string_replace_0_2", 0, 2),
];
pub fn get<'f>(path: &str, f: &'f ATermFactory) -> Option<Vec<Def<'f>>> {
if path == "libstratego-lib" {
Some(SRTS_EXT_NAMES.iter().map(|&(n, s, t)| {
let n = f.intern_string(n);
let sargs: Vec<_> = (0..s).map(|n| f.intern_string(n.to_string())).collect();
let targs: Vec<_> = (0..t).map(|n| f.intern_string(n.to_string())).collect();
let prim_sargs = sargs.iter().map(|&n| Strategy::CallT(n, Vec::new(), Vec::new())).collect();
let prim_targs = targs.iter().map(|&n| BuildTerm::Var(n)).collect();
Def {
name: n,
sargs: sargs,
targs: targs,
body: Strategy::PrimT(n, prim_sargs, prim_targs),
}
}).collect())
} else {
None
}
}
\ No newline at end of file
use context::{TermScope, StrategyScope};
use ctree;
use error::{Result, Error};
use factory::ATermRef;
......@@ -34,79 +33,6 @@ pub fn preprocess(program: ctree::Module) -> Result<Vec<Def>> {
.collect()
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum StrategyDef<'d, 'f: 'd> {
TopLevel(&'d Def<'f>),
Predefined {
def: &'d Def<'f>,
term_scope_offset: usize,
strat_scope_offset: usize,
},
Anonymous {
artificial_name: InternedString<'f>,
body: &'d Strategy<'f>,
term_scope_offset: usize,
strat_scope_offset: usize,
},
}
impl<'d, 'f> StrategyDef<'d, 'f> {
pub fn scope_offsets(&self) -> Option<(usize, usize)> {
match *self {
StrategyDef::TopLevel(_) => None,
StrategyDef::Predefined { term_scope_offset, strat_scope_offset, .. } |
StrategyDef::Anonymous { term_scope_offset, strat_scope_offset, .. } => Some((term_scope_offset, strat_scope_offset)),
}
}
pub fn matching_counts(&self, c_sargs: usize, c_targs: usize) -> bool {
match *self {
StrategyDef::TopLevel(def) |
StrategyDef::Predefined { def, .. } => {
def.sargs.len() == c_sargs && def.targs.len() == c_targs
}
StrategyDef::Anonymous { .. } => c_sargs == 0 && c_targs == 0,
}
}
pub fn build_scope(
&self,
actual_sargs: Vec<StrategyDef<'d, 'f>>,
actual_targs: Vec<ATermRef<'f>>,
) -> (TermScope<'f>, StrategyScope<'d, 'f>) {
match *self {
StrategyDef::TopLevel(def) |
StrategyDef::Predefined { def, .. } => {
(
def.targs.iter().cloned().zip(actual_targs).map(|(n, a)| (n, Some(a))).collect(),
def.sargs.iter().cloned().zip(actual_sargs).collect(),
)
}
StrategyDef::Anonymous { .. } => (FnvHashMap::default(), FnvHashMap::default()),
}
}
pub fn name(&self) -> InternedString<'f> {
match *self {
StrategyDef::TopLevel(def) |
StrategyDef::Predefined { def, .. } => def.name,
StrategyDef::Anonymous { artificial_name, .. } => artificial_name,
}
}
pub fn from_def(def: &'d Def<'f>) -> Self {
StrategyDef::TopLevel(def)
}
pub fn from_let_def(def: &'d Def<'f>, term_scope_offset: usize, strat_scope_offset: usize) -> Self {
StrategyDef::Predefined {
def: def,
term_scope_offset: term_scope_offset,
strat_scope_offset: strat_scope_offset,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Def<'a> {
pub name: InternedString<'a>,
......@@ -157,13 +83,23 @@ impl<'a> ATermWrite for Def<'a> {
// whereas the InternedString gets escaped and quoted like a ctree string should be.
self.sargs
.iter()
.map(|&s| format!("VarDec({}, ConstType(Sort(\"Term\", [])))", string_escape(&s)))
.map(|&s| {
format!(
"VarDec({}, ConstType(Sort(\"Term\", [])))",
string_escape(&s)
)
})
.collect::<Vec<_>>()
.to_ascii(writer)?;
write!(writer, "],[")?;
self.targs
.iter()
.map(|&s| format!("VarDec({}, ConstType(Sort(\"Term\", [])))", string_escape(&s)))
.map(|&s| {
format!(
"VarDec({}, ConstType(Sort(\"Term\", [])))",
string_escape(&s)
)
})
.collect::<Vec<_>>()
.to_ascii(writer)?;
write!(writer, "],")?;
......@@ -240,7 +176,8 @@ impl<'a> Strategy<'a> {
) -> Result<Strategy<'a>> {
use ctree::Strategy as I;
use self::Strategy as O;
let mut map: FnvHashMap<InternedString<'a>, Vec<(Strategy<'a>, Strategy<'a>)>> = FnvHashMap::default();
let mut map: FnvHashMap<InternedString<'a>, Vec<(Strategy<'a>, Strategy<'a>)>> =
FnvHashMap::default();
map.insert(cons, vec![(s_if.try_into()?, s_then.try_into()?)]);
let mut value = s_else;
while let I::GuardedLChoice(s_if, s_then, s_else) = value {
......
This diff is collapsed.
pub mod ctree;
pub mod ir_v1;
pub mod ir_v2;
\ No newline at end of file
pub mod ir_v2;
......@@ -3,7 +3,7 @@
use context::MutContext;
use error::Result;
use factory::ATermRef;
use preprocess::ir_v1::StrategyDef;
use preprocess::ir_v2::StrategyDef;
use phf;
......
......@@ -53,7 +53,6 @@ primitive!(indexedSet_put, 1, 2, (context, sargs, targs, current) => {
let key = &targs[1];
let set: &RefCell<IndexedSet> = set.borrow();
let mut set: RefMut<IndexedSet> = set.borrow_mut();
match set.get(key) {
Some(&index) => {
......
......@@ -10,11 +10,13 @@ mod hash_table;
mod list;
mod term;
mod stacktrace;
mod srts_ext;
pub struct State<'f> {
string: StringState<'f>,
sys: SysState,
hash_table: HashTableState<'f>,
srts_ext: SrtsExtState,
}
impl<'f> State<'f> {
......@@ -25,6 +27,7 @@ impl<'f> State<'f> {
string: StringState::new(),
sys: SysState::new(),
hash_table: HashTableState::new(),
srts_ext: SrtsExtState::new(),
}
}
}
......@@ -46,3 +49,5 @@ pub use self::list::*;
pub use self::term::*;
pub use self::stacktrace::*;
pub use self::srts_ext::*;
......@@ -2,7 +2,7 @@ macro_rules! primitive {
($name:ident, ($context:ident, $current:ident) => $body:block) => {
pub fn $name<'d, 'f: 'd>(
$context: &::context::MutContext<'d, 'f>,
_sargs: &[::preprocess::ir_v1::StrategyDef<'d, 'f>],
_sargs: &[::preprocess::ir_v2::StrategyDef<'d, 'f>],
_targs: &[::factory::ATermRef<'f>],
$current: ::factory::ATermRef<'f>,
) -> ::error::Result<::factory::ATermRef<'f>> {
......@@ -12,7 +12,7 @@ macro_rules! primitive {
($name:ident, $targs_no:expr, ($context:ident, $targs:ident, $current:ident) => $body:block) => {
pub fn $name<'d, 'f: 'd>(
$context: &::context::MutContext<'d, 'f>,
_sargs: &[::preprocess::ir_v1::StrategyDef<'d, 'f>],
_sargs: &[::preprocess::ir_v2::StrategyDef<'d, 'f>],
$targs: &[::factory::ATermRef<'f>],
$current: ::factory::ATermRef<'f>,
) -> ::error::Result<::factory::ATermRef<'f>> {
......@@ -25,7 +25,7 @@ macro_rules! primitive {
($name:ident, $sargs_no:expr, 0, ($context:ident, $sargs:ident, $current:ident) => $body:block) => {
pub fn $name<'d, 'f: 'd>(
$context: &::context::MutContext<'d, 'f>,
$sargs: &[::preprocess::ir_v1::StrategyDef<'d, 'f>],
$sargs: &[::preprocess::ir_v2::StrategyDef<'d, 'f>],
_targs: &[::factory::ATermRef<'f>],
$current: ::factory::ATermRef<'f>,
) -> ::error::Result<::factory::ATermRef<'f>> {
......@@ -38,7 +38,7 @@ macro_rules! primitive {
($name:ident, $sargs_no:expr, $targs_no:expr, ($context:ident, $sargs:ident, $targs:ident, $current:ident) => $body:block) => {
pub fn $name<'d, 'f: 'd>(
$context: &::context::MutContext<'d, 'f>,
$sargs: &[::preprocess::ir_v1::StrategyDef<'d, 'f>],
$sargs: &[::preprocess::ir_v2::StrategyDef<'d, 'f>],
$targs: &[::factory::ATermRef<'f>],
$current: ::factory::ATermRef<'f>,
) -> ::error::Result<::factory::ATermRef<'f>> {
......@@ -55,7 +55,7 @@ macro_rules! primitive {
#[inline]
pub fn $name<'d, 'f: 'd>(
context: &::context::MutContext<'d, 'f>,
sargs: &[::preprocess::ir_v1::StrategyDef<'d, 'f>],
sargs: &[::preprocess::ir_v2::StrategyDef<'d, 'f>],
targs: &[::factory::ATermRef<'f>],
current: ::factory::ATermRef<'f>,
) -> ::error::Result<::factory::ATermRef<'f>> {
......@@ -65,7 +65,7 @@ macro_rules! primitive {
($name:ident, ($context:ident, $sargs:ident, $targs:ident, $current:ident) => $body:block) => {
pub fn $name<'d, 'f: 'd>(
$context: &::context::MutContext<'d, 'f>,
$sargs: &[::preprocess::ir_v1::StrategyDef<'d, 'f>],
$sargs: &[::preprocess::ir_v2::StrategyDef<'d, 'f>],
$targs: &[::factory::ATermRef<'f>],
$current: ::factory::ATermRef<'f>,
) -> ::error::Result<::factory::ATermRef<'f>> {
......
use error::Error;
use interpreter::eval_sdef;
use aterm::ATermFactory as ATF;
pub struct SrtsExtState {
new_counter: u16,
}
impl SrtsExtState {
pub fn new() -> Self {
SrtsExtState {
new_counter: 0,
}
}
}
primitive!(SRTS_EXT_at_end_1_0, 1, 0, (context, sargs, current) => {
let list = current.get_term_list().ok_or(Error::StrategyFailed)?;
let tail = eval_sdef(&sargs[0], context, Vec::new(), vec![context.factory.nil()], current)?;
let tail = tail.get_term_list().ok_or(Error::StrategyFailed).map_err(|e|{
eprintln!("Warning: trying to build list with illegal tail: {}", tail);
e
})?;
Ok(context.factory.list_term(list.with_tail(tail.clone())))
});
primitive!(SRTS_EXT_concat_0_0, (context, current) => {
unimplemented!()
});
primitive!(SRTS_EXT_crush_3_0, 3, 0, (context, sargs, current) => {
unimplemented!()
});
primitive!(SRTS_EXT_eq_ignore_annos_0_1, 1, (context, targs, current) => {
unimplemented!()
});
primitive!(SRTS_EXT_fatal_err_0_3, 3, (context, targs, current) => {
unimplemented!()
});
primitive!(SRTS_EXT_filter_1_0, 1, 0, (context, sargs, current) => {
unimplemented!()
});
primitive!(SRTS_EXT_flatten_list_0_0, (context, current) => {
unimplemented!()
});
primitive!(SRTS_EXT_newint_0_0, (context, current) => {
let mut ssl_state = context.ssl_state.borrow_mut();
let newint = ssl_state.srts_ext.new_counter;
ssl_state.srts_ext.new_counter += 1;
Ok(context.factory.int(newint as i32))
});
primitive!(SRTS_EXT_repeat_1_0, 1, 0, (context, sargs, current) => {
unimplemented!()
});
primitive!(SRTS_EXT_string_replace_0_2, 2, (context, targs, current) => {
unimplemented!()
});
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment