#!/usr/bin/perl -w use strict; use List::Util qw[min max sum]; use Getopt::Long qw(GetOptions); use Data::Dumper; my %options = (); GetOptions( \%options, "depth-max=i", "child-max=i", "events-max=i", "states-max=i", "trans-max=i", "random-seed=i" ); my $seed = $options{'random-seed'} || int(rand(2**31)); my $maxDepth = $options{'depth-max'} || 6; my $maxChilds = $options{'child-max'} || 6; my $maxStates = $options{'states-max'} || 60; my $maxTrans = $options{'trans-max'} || 6; my $maxEvents = $options{'trans-max'} || int($maxStates / 3) + 1; # $maxStates = 8; # $maxTrans = 8 srand($seed); my $machine; my $stateId = 0; my $probs = { 'state' => { 'type' => { 'history' => 2, 'parallel' => 2, 'state' => 5, 'final' => 1 } }, 'transition' => { 'target' => 0.8, 'event' => 0.7, 'cond' => 0.9, 'execContent' => 0.7, }, 'history' => { 'deep' => 0.4 } }; my $sumChildProbs = sum( values(%{$probs->{'state'}->{'type'}})); sub putMachine { my $where = shift; $$where->{'name'} = 'test'; $$where->{'type'} = 'scxml'; $$where->{'datamodel'} = 'ecmascript'; putState(\$$where->{'children'}, 0); putTransition(\$$where); } sub putTransition { my $where = shift; return if $$where->{'type'} eq 'final'; my $nrTrans = int(rand($maxTrans + 1)); $nrTrans = min($nrTrans, 1) if $$where->{'type'} eq 'history'; for (my $i = 0; $i < $nrTrans; $i++) { my $trans; if (rand(1) < $probs->{'transition'}->{'target'}) { # has a target - pick one at random $trans->{'target'} = 'id' . int(rand($stateId)); } if (rand(1) < $probs->{'transition'}->{'event'}) { # has an event $trans->{'event'} = 'e' . int(rand($maxEvents + 1)); } if (rand(1) < $probs->{'transition'}->{'cond'}) { # has a condition if (int(rand(2)) > 0) { $trans->{'cond'} = 'true'; } else { $trans->{'cond'} = 'false'; } } if (rand(1) < $probs->{'transition'}->{'execContent'}) { # has a executable content push @{$trans->{'execContent'}}, ''; } push @{$$where->{'transitions'}}, $trans; } # continue with childs foreach (@{$$where->{'children'}}) { putTransition(\$_); } } sub putState { my $where = shift; my $depth = shift; my $minStates = shift || 0; my $r; return if ($stateId > $maxStates); return if ($depth > $maxDepth); my $nrChilds = int(rand($maxChilds + 1)); $nrChilds = max($minStates, $nrChilds); for (my $i = 0; $i < $nrChilds; $i++) { my $r = rand($sumChildProbs); my $state; foreach my $type (keys %{$probs->{'state'}->{'type'}}) { my $prob = $probs->{'state'}->{'type'}->{$type}; if ($r < $prob) { $state->{'type'} = $type; last; } $r -= $prob; } $state->{'id'} = "id".$stateId++; if ($state->{'type'} eq 'parallel') { putState(\$state->{'children'}, $depth + 1, 2); } elsif ($state->{'type'} eq 'state') { putState(\$state->{'children'}, $depth + 1); } elsif ($state->{'type'} eq 'history') { if (rand(1) < $probs->{'history'}->{'deep'}) { $state->{'deep'} = 1; } } push @{$$where}, $state; } }; sub writeState { my $state = shift; print STDOUT '<'.$state->{'type'}; print STDOUT ' id="'.$state->{'id'} . '"'; print STDOUT ' type="deep"' if exists $state->{'deep'}; print STDOUT '>'; foreach (@{$state->{'children'}}) { writeState($_); } # foreach (@{$state->{'transitions'}}) { # writeTransition($_); # } print STDOUT '{'type'} . '>'; }; sub writeTransition { my $trans = shift; print STDOUT '{'target'}; print STDOUT ' event="' . $trans->{'event'} . '"' if $trans->{'event'}; print STDOUT ' cond="' . $trans->{'cond'} . '"' if $trans->{'cond'}; if ($trans->{'execContent'}) { print STDOUT '>'; foreach (@{$trans->{'execContent'}}) { print STDOUT $_; } print STDOUT ''; } else { print STDOUT '/>'; } }; sub writeMachine { my $machine = shift; print STDOUT '{'datamodel'}; print STDOUT ' seed="' . $seed . '"'; print STDOUT ' name="' . $machine->{'name'} . '"' if $machine->{'name'}; print STDOUT '>'; foreach (@{$machine->{'children'}}) { writeState($_); } print STDOUT ''; } putMachine(\$machine); # print Dumper($machine); writeMachine($machine); #print Dumper($machine); # writeState($machine);