diff options
| author | Shinya Sato <shinnya.sato@gmail.com> | 2022-07-21 14:59:34 +0900 |
|---|---|---|
| committer | Shinya Sato <shinnya.sato@gmail.com> | 2022-07-21 14:59:34 +0900 |
| commit | 4753a3914675dd8a3dfb8233062f90b65520ba4e (patch) | |
| tree | 3632b01a2caa682c45962fad114f7b7504ea2c1f | |
| parent | c57cb1fd511d2c69bf332324c73608f309bb4772 (diff) | |
| parent | 1f51c41a32e190d483ff336c34eb63acda27cbb6 (diff) | |
| download | inpla-4753a3914675dd8a3dfb8233062f90b65520ba4e.tar.gz inpla-4753a3914675dd8a3dfb8233062f90b65520ba4e.zip | |
Merge branch 'develop'
| -rw-r--r-- | Changelog.md | 37 | ||||
| -rw-r--r-- | Gentle_introduction_Inpla.md (renamed from How_to_write_programs.md) | 126 | ||||
| -rw-r--r-- | README.md | 6 | ||||
| -rw-r--r-- | sample/hanoi.in | 49 | ||||
| -rw-r--r-- | sample/nqueen.in | 141 | ||||
| -rw-r--r-- | src/inpla.y | 187 |
6 files changed, 442 insertions, 104 deletions
diff --git a/Changelog.md b/Changelog.md index d19faa5..c796a01 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,23 +1,32 @@ # Change log -### v0.8.3 (released on 19 July 2022) -#### New Features +### v0.8.3-1 minor update (released on 21 July 2022) +#### Polished +* **Built-in agent** `Dup`: it can duplicate attributes also immediately. For instance, with respect to `Cons(int, xs)`, it performs as follows: + ``` + Dup(a1,a2) >< (int i):xs => a1~i:w1, a2~i:w2, Dup(w1,w2)~xs; + ``` + -* **A built-in agent** `Dup`: it duplicates any nets gradually with the following rules: - -``` ->>> Dup(a1,a2) ~ [1,2,3]; -(7 interactions, 0.00 sec) ->>> ifce; -a1 a2 -Connections: -a1 ->[1,2,3] -a2 ->[1,2,3] +### v0.8.3 (released on 19 July 2022) +#### New Features ->>> -``` +* **Built-in agent** `Dup`: it duplicates any nets gradually with the following rules: + + ``` + >>> Dup(a1,a2) ~ [1,2,3]; + (7 interactions, 0.00 sec) + >>> ifce; + a1 a2 + + Connections: + a1 ->[1,2,3] + a2 ->[1,2,3] + + >>> + ``` ### v0.8.2-2 minor update (released on 30 May 2022) diff --git a/How_to_write_programs.md b/Gentle_introduction_Inpla.md index 3f0cd27..b64adc5 100644 --- a/How_to_write_programs.md +++ b/Gentle_introduction_Inpla.md @@ -1,4 +1,4 @@ -# Gentle introduction to programming in Inpla +# Gentle introduction to Inpla #### Contents in this section * [Nets: terms and connections](#nets-terms-and-connections) * [Interaction rules: rewriting rules for nets](#interaction-rules-rewriting-rules-for-nets) @@ -12,7 +12,10 @@ - [Interaction rules with conditions on attributes](#interaction-rules-with-conditions-on-attributes) * [Commands](#commands) * [Execution Options](#execution-options) - +* [Advanced topics](#advanced-topics) + - [Reuse annotations](#reuse-annotations) + - [built-in agents more](#built-in-agents-more) + - [Weak reduction strategy](#weak-reduction-strategy) @@ -130,21 +133,31 @@ Something complicated? No problem! Let's us learn how to define the rules with s ### Example: Operations on unary natural numbers -Unary natural numbers are built by Z and S. For instance, 0, 1, 2, 3 are expressed as Z, S(Z), S(S(Z)), S(S(S(Z))). Here, let's think about an increment operation `inc` such that inc(n) = S(n). This is written as rules for Z and S(x) as follows: +Unary natural numbers are built by Z and S. For instance, 0, 1, 2, 3 are expressed as Z, S(Z), S(S(Z)), S(S(S(Z))). Here, let's think about an increment operation "inc" such that: +``` + inc(n) = S(n). + ``` + +First, we will think about the relationship between constructors and deconstructors in this computation. +Here, constructors are agents `Z`, `S(x)`, and a destructor is `inc(r)` which has an argument for the output. The behaviour of `inc(r)` will be as follows: +* When `inc(r)` meets `Z`, the output `r` is connected to `S(Z)`. +* In the case of `S(x)`, the `r` is connected to `S(S(x))`. + + This is written as the followint rules: ``` -inc(ret) >< Z => ret~S(Z); -inc(ret) >< S(x) => ret~S(S(x)); +inc(r) >< Z => r~S(Z); +inc(r) >< S(x) => r~S(S(x)); ``` -In the first rule, the name `ret` occurs twice, so it satisfies the rule proviso. The second rule is also OK because the `ret` and `x` are distinct and occur twice in the rule. +Let's check the rule proviso. In the first rule, the name `r` occurs twice, so it satisfies the proviso. The second rule is also OK because the `r` and `x` are distinct and occur twice in the rule. For agents can work as constructors and de-constructors, it could be good to use strings start from a capital letter such as `Z`, `S` and `Tree`, and all small letters for de-constructors such as `inc`. Let's take the result of the increment operation for `S(S(Z))`: ``` ->>> inc(r)~S(S(Z)); // This is also written as: r << inc(S(S(Z))) +>>> inc(r)~S(S(Z)); (1 interactions, 0.01 sec) >>> r; S(S(S(Z)) @@ -442,7 +455,7 @@ In interaction rules, attributes are recognised by using variables with a modifi -**We have to be careful for operations of two attributes on distinct agents**. For instance, we take the following rule of an `add` agent: +**We should be careful for operations of two attributes on distinct agents**. For instance, we take the following rule of an `add` agent: ``` >>> add(result, int b) >< (int a) => result~(a+b); @@ -471,7 +484,7 @@ If the `add(r, b)~3` is operated first, it causes the runtime error because the >>> add(result, b) >< (int a) => addn(result, a) ~ b; >>> addn(result, int a) >< (int b) => r~(a+b); ``` -Do not worry about it. Some built-in rules are prepared as follows: +Do not worry about it. Some built-in rules for arithmetic computations are prepared as follows: ### Built-in rules of attributes in the anonymous agents @@ -486,7 +499,7 @@ _Add(result, int x)><(int y) => result~(x+y); * Example: ``` - >>> Add(r,3)~5; // Add is already defined as built-in. + >>> Add(r,3)~5; // Add is already defined as built-in. >>> r; 8 >>> Sub(r1, r)~2; // It is also written as an abbreviation form: r1<<Sub(r,2); @@ -498,7 +511,7 @@ _Add(result, int x)><(int y) => result~(x+y); ### Interaction rules with conditions on attributes -In interaction rules, conditional rewritings on attributes are available. The following is a general form: +Conditional rewritings on attributes are available. The following is a general form: ``` <rule-with-conditions> ::= @@ -610,3 +623,94 @@ Inpla has the following macro: * The option ```-t``` is available for the multi-thread version that is compiled by ```make thread```. The default value is setting for the number of cores, so execution will be automatically scaled without specifying this. +## Advanced topics + +### Reuse annotations +In interaction rule definitions, we can specify how active pair agents are reused by putting annotations `(*L)` and `(*R)` before agents in the right-hand side net. This annotations promote in-place computing, and as a result performance can be improved well in parallel execution. + +* For instance, in the rule `gcd(ret) >< (int a, int b)`, we can reuse the `gcd` and `Tuple2` in nets as follows: + + ``` + gcd(ret) >< (int a, int b) + | b==0 => ret ~ a + | _ => (*L)gcd(ret) ~ (*R)(b, a%b); + ``` + + +### Built-in agents more +* **Merger agent** `Marger`: +it merges two lists into one. Merger agent has two principal ports that can take the two distinct lists. Interactions with the lists are performed as soon as one of the principal ports is connected one of the lists. So, the merged result is non-deterministically decided, especially in multi-threaded execution. + +  + + We overload `<<` in order to use the Merger agent naturally as follows: + + ``` + ret << Merger(alist, blist) + ``` + + The following is an execution example (the count of interactions is not supported yet): + ``` + >>> r << Merger([0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1]); + (1 interactions by 4 threads, 0.10 sec) + >>> ifce; + r + + Connections: + r ->[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0] + + >>> + ``` + +### Weak reduction strategy + +In this reduction strategy, only connections that have interface names (thus, live and occur once) are evaluated. This is taken for non-terminate computation such as fixed point combinator and process networks. + +* Example: We have a sample net in `sample/processnet1.in` that keep producing natural numbers from 1 and output these to the port `r`: + + ``` + // Rules + dup(a1,a2) >< (int i):xs => a1~(i:xs1), a2~(i:xs2), dup(xs1,xs2)~xs; + dup(a1,a2) >< [] => a1~[], a2~[]; + + inc(r) >< (int i):xs => r~(i+1):w, inc(w)~xs; + inc(r) >< [] => r~[]; + + // Nets + dup(r,w)~r1, inc(r1) ~ 0:w; + + // +-----+ +-----+ +---+ + // r ----| | r1 | | | | + // | dup |--->---| inc |---><---| 0 |----+ + // +---| | | | | | | + // | +-----+ +-----+ +---+ | + // | | + // +-----------------------------------------+ + // w + ``` + + This reduction strategy is available by invoking with `-w` option as follows: + + ``` + $ ./inpla -w + Inpla 0.5.0 (Weak Strategy) : Interaction nets as a programming language [28 Oct. 2021] + >>> use "sample/processnet1.in"; + (2 interactions, 0.00 sec) + >>> ifce; + r + + Connections: + r ->[1,<a1>... // this means a list of 1 and something. + + >>> a:b ~ r; + (2 interactions, 0.00 sec) + >>> ifce; + a b + + Connections: + a ->1 + b ->[2,<b1>... + + >>> + ``` +
\ No newline at end of file @@ -6,7 +6,7 @@ Inpla is a multi-threaded parallel interpreter of interaction nets. Once you write programs for sequential execution, it works also in multi-threaded parallel execution. Each thread is managed on each CPU-core with POSIX-thread library. -* The current version is 0.8.3, released on **19 July 2022**. (See [Changelog.md](Changelog.md) for details.) +* The current version is 0.8.3-1 (minor update), released on **21 July 2022**. (See [Changelog.md](Changelog.md) for details.) * The below graph shows speed-up ratio to threads numbers for programs in the following benchmark table.  @@ -30,7 +30,7 @@ Inpla is a multi-threaded parallel interpreter of interaction nets. Once you wri - The above table contains execution time in second on average of ten times execution by using Linux PC (Core i7-9700 (8 threads, no Hyper-threading), 16GB memory). The fastest one is shown with bold style. Scripts for the comparison table are in the `comparison` directory. - - Inpla8 and Inpla8r mean 8 threads without/with [reuse-annotated](#Reuse-annotations) execution, respectively. + - Inpla8 and Inpla8r mean 8 threads without/with [reuse-annotated](./Gentle_introduction_Inpla.md#reuse-annotations) execution, respectively. - "ack(3,11)" is computation of Ackermann function. Execution time of Python is a blank due to stack size limitation error. @@ -262,7 +262,7 @@ Inpla is a multi-threaded parallel interpreter of interaction nets. Once you wri ## How to write programs in Inpla -[How_to_write_programs.md](How_to_write_programs.md) explains how to make programs in Inpla step by step. Please see it! +[Gentle_introduction_Inpla.md](Gentle_introduction_Inpla.md) explains how to make programs in Inpla step by step. Please look it over! ## Updates diff --git a/sample/hanoi.in b/sample/hanoi.in index 665b2da..40cef50 100644 --- a/sample/hanoi.in +++ b/sample/hanoi.in @@ -1,42 +1,27 @@ // Tower of Hanoi Puzzle // Rules -hanoi(return, source, target, auxiliary) >< (int n) -| n==0 => return~[], Eraser~source, Eraser~target, Eraser~auxiliary -| _ => source ~ Dup(src1, Dup(src2, src3)), - target ~ Dup(tgt1, Dup(tgt2, tgt3)), - auxiliary ~ Dup(aux1, aux2), - hanoi(ret1, src1, aux1, tgt1)~(n-1), - hanoi(ret2, aux2, tgt2, src2)~(n-1), - Append(return, (n,src3,tgt3):ret2)~ret1; - // This Append is a bulit-in agent. +hanoi(return, source, target, aux) >< (int n) +| n==0 => + // Erase the source, target and aux + Eraser~source, Eraser~target, Eraser~aux, + // result + return~[] -// The Dup is defined as built-in: -// Dup(a,b)><A => a~A, b~A; -// Dup(a,b)><B => a~B, b~B; -// Dup(a,b)><C => a~C, b~C; +| _ => + // Duplicate the source, target and aux + source ~ Dup(src1, Dup(src2, src3)), + target ~ Dup(tgt1, Dup(tgt2, tgt3)), + aux ~ Dup(aux1, aux2), -// The `Eraser' is defined as a built-in agent for any agents as follows: -//Eraser >< Alpha(a1, ..., a5) => Eraser~a1, ..., Eraser~a5; + // recursive applications + hanoi(ret1, src1, aux1, tgt1)~(n-1), + hanoi(ret2, aux2, tgt2, src2)~(n-1), + + // result + return << Append(ret1, (n,src3,tgt3):ret2); // Net hanoi(result, A, C, B) ~ 3; result; // should be [(1,A,C),(2,A,B),(1,C,B),(3,A,C),(1,B,A),(2,B,C),(1,A,C)] - - -// These are also written using abbreviation as follows: -// hanoi(return, source, target, auxiliary) >< (int n) -// | n==0 => return~[], -// << Eraser(source), << Eraser(target), << Eraser(auxiliary) -// | _ => src1, Dup(src2, src3) << Dup(source), -// tgt1, Dup(tgt2, tgt3) << Dup(target), -// aux1, aux2 << Dup(auxiliary), -// ret1 << hanoi(src1, aux1, tgt1, n-1), -// ret2 << hanoi(aux2, tgt2, src2, n-1), -// return << Append(ret1, (n,src3,tgt3):ret2); -// -// result << hanoi(A, C, B, 3); -// result; - - diff --git a/sample/nqueen.in b/sample/nqueen.in new file mode 100644 index 0000000..03b2463 --- /dev/null +++ b/sample/nqueen.in @@ -0,0 +1,141 @@ +// N-Queen +// +// The original is written as a Lisp program in the following file: +// https://www.istc.kobe-u.ac.jp/activity/mage/m27/27_Lisp.pdf + + +/** + * member + * r, done << member(m, list) + * return + * r: 1 if m occurs in list + * done: the same to `list' + */ +// fun member x [] = false +// | member x (y::ys) = if x=y then true else (member x ys); + +member(r, list, int x) >< [] => + r~0, list~[]; +member(r, list, int x) >< (int y):ys +| x==y => + r~1, list~y:ys +| _ => + list~y:cnt, member(r, cnt, x)~ys; + + +/** + * len_list (stream version) + * len, done << len_list(list) + * return + * len: length of `list' + * done: the same to `list' + */ + +len_list(len, done) >< [] => + len~0, done~[]; +len_list(len, done) >< x:xs => + done~x:cnt, + len_list_(len, cnt, 1)~xs; + +len_list_(len, done, int ct) >< [] => + len~ct, done~[]; +len_list_(len, done, int ct) >< x:xs => + done~x:cnt, + len_list_(len, cnt, ct+1) ~ xs; + +/** + * len (non-stream version) + * ret << len(list) + * return + * ret: length of `list' + */ + +len(ret) >< [] => + ret~0; +len(ret) >< x:xs => + len_list(ret, Eraser)~x:xs; + + + +/** + * threat (stream version) + * check for (0,q) and (k, qpos[col=k]) where k=1... + * http://www.nct9.ne.jp/m_hiroi/func/haskell06.html + 0 1 2 --> + +------------- + 1| . . . . . . + 2| . . . -3. . 5 - 3 = 2 + 3| . . -2. . . 5 - 2 = 3 + 4| . -1. . . . 5 - 1 = 4 + 5| Q . . . . . Q position is 5 + 6| . +1. . . . 5 + 1 = 6 + 7| . . +2. . . 5 + 2 = 7 + 8| . . . +3. . 5 + 2 = 8 + +------------- + * r, done << threat(k,m, board) + * return + * r: 1 if threat conditions are satisfied + * done: the same to `board' + */ +// fun threat k m [] = false +// | threat k m (x::xs) = +// if (k = x-m) orelse (k = x+m) then true +// else (threat (k+1) m xs); + +threat(r, done, int k, int q)><[] => + r~0, done~[]; +threat(r, done, int k, int q)><(int x):xs +| (k == x-q) or (k == q-x) => + r~1, done~(x:xs) +| _ => + done~x:cnt, threat(r, cnt, k+1, q)~xs; + + + +// fun queen1 b n 0 = [] +// | queen1 b n m = +// if (member m b) orelse (threat 1 m b) then (queen1 b n (m-1)) +// else if (length b) = (n-1) then (m::b)::(queen1 b n (m-1)) +// else (queen1 (m::b) n n) @ (queen1 b n (m-1)); +// fun queen n = queen1 n [] n; + +queen(ret) >< (int n) => queen_(ret, [], n)~n; + +queen_(r, b, int n) >< (int m) +| m==0 => + r~[], Eraser~b +| _ => + mem_ret, done_b << member(m,b), + queen__chk_m_in_b(r, done_b, n, m)~mem_ret; + +queen__chk_m_in_b(r, b, int n, int m) >< (int mem_ret) +| mem_ret == 1 => + queen_(r, b, n)~(m-1) +| _ => + th_ret, done_b << threat(1, m, b), + queen__chk_threat(r, done_b, n, m)~th_ret; + +queen__chk_threat(r, b, int n, int m) >< (int threat_ret) +| threat_ret == 1 => + queen_(r, b, n)~(m-1) +| _ => + len_ret, done_b << len_list(b), + queen__chk_lastelem(r, done_b, n, m)~len_ret; + +queen__chk_lastelem(r, b, int n, int m) >< (int len_ret) +| len_ret == n-1 => + b1, b2 << Dup(b), + r~(m:b1):cnt, queen_(cnt, b2, n)~(m-1) +| _ => + b1, b2 << Dup(b), + r << Append(cnt1, cnt2), + queen_(cnt1, m:b1, n)~n, queen_(cnt2, b2, n)~(m-1); + + + +// ---------------------------------------------------------- +// main +// ---------------------------------------------------------- +const N=8; +queen(ret)~N, len(count)~ret; +count; diff --git a/src/inpla.y b/src/inpla.y index 79e460e..bc9cfc2 100644 --- a/src/inpla.y +++ b/src/inpla.y @@ -22,8 +22,8 @@ // ---------------------------------------------- -#define VERSION "0.8.3" -#define BUILT_DATE "19 July 2022" +#define VERSION "0.8.3-1" +#define BUILT_DATE "21 July 2022" // ------------------------------------------------------------------ @@ -9103,32 +9103,89 @@ loop_agent_a1_a2_this_order: a1=a1p; goto loop; } + + // a2p0 などが fixint の場合は即座に複製させる case 1: { // Dup(p0,p1) >< A(a2p0) => p1~A(w2), p0~A(w1), - // Dup(w1,w2)~a2p0; + // Dup(w1,w2)~a2p0; + // Dup(p0,p1) >< A(int a2p0) => p1~A(a2p0), p0~A(a2p0); + + VALUE a2p0 = AGENT(a2)->port[0]; + int a2id = BASIC(a2)->id; // p1 VALUE new_a2 = make_Agent(vm, a2id); - VALUE w = make_Name(vm); - AGENT(new_a2)->port[0] = w; - PUSH(vm, AGENT(a1)->port[1], new_a2); - AGENT(a1)->port[1] = w; - - // p0 - w = make_Name(vm); - AGENT(a2)->port[0] = w; - PUSH(vm, AGENT(a1)->port[0], a2); - AGENT(a1)->port[0] = w; - a2 = a2p0; - goto loop; + if (IS_FIXNUM(a2p0)) { + AGENT(new_a2)->port[0] = a2p0; + PUSH(vm, AGENT(a1)->port[1], new_a2); + AGENT(a2)->port[0] = a2p0; + + VALUE a1p0 = AGENT(a1)->port[0]; + free_Agent(a1); + + //PUSH(vm, a1p0, a2); + a1 = a1p0; + goto loop; + + } else { + VALUE w = make_Name(vm); + AGENT(new_a2)->port[0] = w; + PUSH(vm, AGENT(a1)->port[1], new_a2); + AGENT(a1)->port[1] = w; // for (*L)dup + + w = make_Name(vm); + AGENT(a2)->port[0] = w; + PUSH(vm, AGENT(a1)->port[0], a2); + + AGENT(a1)->port[0] = w; // for (*L)dup + + a2 = a2p0; + goto loop; + } + } + break; + case 2: + { + // Dup(p0,p1) >< Cons(int i, a2p1) => + // p0~Cons(i,w), p1~(*R)Cons(i,ww), (*L)Dup(w,ww)~a2p1; + + VALUE a2p0 = AGENT(a2)->port[0]; + if (IS_FIXNUM(a2p0)) { + int a2id = BASIC(a2)->id; + VALUE new_a2 = make_Agent(vm, a2id); + + AGENT(new_a2)->port[0] = a2p0; + + VALUE w = make_Name(vm); + AGENT(new_a2)->port[1] = w; + + PUSH(vm, AGENT(a1)->port[0], new_a2); + AGENT(a1)->port[0] = w; + + VALUE a2p1 = AGENT(a2)->port[1]; + VALUE ww = make_Name(vm); + AGENT(a2)->port[1] = ww; + + PUSH(vm, AGENT(a1)->port[1], a2); + AGENT(a1)->port[1] = ww; + + a2 = a2p1; + goto loop; + } + + // otherwise: goto default + // So, DO NOT put break. + } + + default: { // Dup(p0,p1) >< A(a2p0, a2p1) => @@ -9146,56 +9203,98 @@ loop_agent_a1_a2_this_order: // Dup(w2,ww2)~a2p2, // Dup(w3,ww3)~a2p3; + + // Dup(p0,p1) >< A(a2p0, int a2p1, a2p2 a2p3) => + // p0~A(w0,a2p1,w2,w3), (*L)Dup(w0,ww0)~a2p0 + // p1~(*R)A(ww0,a2p1,ww2,ww3), + // Dup(w2,ww2)~a2p2, + // Dup(w3,ww3)~a2p3; + + // newA = mkAgent(A); - // for (i=0; i<arity; i++) { newA->p[i] = w_i; } - // + // for (i=0; i<arity; i++) { + // if (!IS_FIXNUM(a2->p[i])) { + // newA->p[i] = w_i; + // } else { + // newA->p[i] = a2->p[i]; + // } + // } // for (i=1; i<arity; i++) { - // newDup( newA->p[i], newWW_i) ~ a2[i] - // a2[i] = newWW_i; + // if (!IS_FIXNUM(a2->p[i])) { + // newDup( newA->p[i], newWW_i) ~ a2[i] + // a2[i] = newWW_i; + // } // } - // p0_preserve = p0; - // p1_preserve = p1; - // (*L)Dup(w0, newWW0) ~ a2[0] // this destroys the p0 and p1. + // if (!IS_FIXNUM(a2->p[0])) { + // p0_preserve = p0; + // p1_preserve = p1; + // (*L)Dup(w0, newWW0) ~ a2[0] // this destroys the p0 and p1. // - // p0_preserve ~ newA - // a2[0] = newWW0; - - // p1_preserve ~ a2; <-- This will be `goto loop`. - + // p0_preserve ~ newA + // a2[0] = newWW0; + // + // p1_preserve ~ a2; <-- This will be `goto loop'. + // } else { + // p0 ~ newA; + // p1_preserve = p1; + // free_Agent((*L)Dup); + // p1_preserve ~ a2; >-- This will be `goto loop'. + // } int a2id = BASIC(a2)->id; VALUE new_a2 = make_Agent(vm, a2id); for (int i=0; i<arity; i++) { - AGENT(new_a2)->port[i] = make_Name(vm); + VALUE a2pi = AGENT(a2)->port[i]; + if (!IS_FIXNUM(a2pi)) { + AGENT(new_a2)->port[i] = make_Name(vm); + } else { + AGENT(new_a2)->port[i] = a2pi; + } } for (int i=1; i<arity; i++) { - VALUE new_dup = make_Agent(vm, ID_DUP); - AGENT(new_dup)->port[0] = AGENT(new_a2)->port[i]; + VALUE a2pi = AGENT(a2)->port[i]; - VALUE new_ww = make_Name(vm); - AGENT(new_dup)->port[1] = new_ww; + if (!IS_FIXNUM(a2pi)) { + + VALUE new_dup = make_Agent(vm, ID_DUP); + AGENT(new_dup)->port[0] = AGENT(new_a2)->port[i]; - PUSH(vm, new_dup, AGENT(a2)->port[i]); + VALUE new_ww = make_Name(vm); + AGENT(new_dup)->port[1] = new_ww; + + PUSH(vm, new_dup, a2pi); - AGENT(a2)->port[i] = new_ww; + AGENT(a2)->port[i] = new_ww; + } } + + VALUE a2p0 = AGENT(a2)->port[0]; + if (!IS_FIXNUM(a2p0)) { - VALUE a1p0 = AGENT(a1)->port[0]; - VALUE a1p1 = AGENT(a1)->port[1]; + VALUE a1p0 = AGENT(a1)->port[0]; + VALUE a1p1 = AGENT(a1)->port[1]; - AGENT(a1)->port[0] = AGENT(new_a2)->port[0]; - VALUE new_ww = make_Name(vm); - AGENT(a1)->port[1] = new_ww; - PUSH(vm, a1, AGENT(a2)->port[0]); + AGENT(a1)->port[0] = AGENT(new_a2)->port[0]; + VALUE new_ww = make_Name(vm); + AGENT(a1)->port[1] = new_ww; + PUSH(vm, a1, a2p0); - PUSH(vm, a1p0, new_a2); + PUSH(vm, a1p0, new_a2); - AGENT(a2)->port[0] = new_ww; + AGENT(a2)->port[0] = new_ww; - a1 = a1p1; + a1 = a1p1; - goto loop; + goto loop; + } else { + PUSH(vm, AGENT(a1)->port[0], new_a2); + VALUE a1p1 = AGENT(a1)->port[1]; + free_Agent(a1); + + a1=a1p1; + goto loop; + } } |
