Macros
A macro is not an operator. The compiler replaces the call with the body of the macro before it writes the target code. The macros below are in lib/stdops.rgr.
How the compiler selects a macro
Section titled “How the compiler selects a macro”A defn declaration gives no type to its parameters. The name and the
number of parameters is all that the declaration states, so several macros
can hold the same name and the same number of parameters. This file holds
four such names.
The compiler selects one of them at the call site, and it selects by trial.
These are the steps, from TransformOpFn in
compiler/RangerFlowParser.rgr:
- The compiler collects every macro with that name.
- A macro with a
?in a type becomes one candidate per type:string,int,double,booleanand each class of the program. A class whose name is in the text of the call comes first. - The compiler removes the candidates that take a different number of arguments. This is the only test before the trial.
- The compiler expands the body of the first candidate into the call site and compiles it. The compilation is a test: the compiler counts the new errors.
- A candidate that makes no new error is the result, and the expansion stays. The compiler does not try the candidates after it.
- A candidate that makes an error is removed together with its errors, and the compiler tries the next candidate. It keeps the errors of the candidate with the fewest of them.
- When no candidate fits, the compiler reports the errors of that
candidate, and then
Could not find suitable match for the operator node.
A macro that expands into itself stops at depth 20 with
Error: max recursiion depth of > 20 for inline operators detected.
What this means for a program
Section titled “What this means for a program”A macro states its requirements only in its body. Nothing in
defn ForEach (list f) says that list is an array or a hash map. The body
of one of them calls keys and get, which a hash map accepts and an array
does not, and the body of the other calls size and at. The compiler finds
this out when it compiles the expansion, not before.
The order of the declarations decides. Two macros can both fit one call. The first one that fits is the result.
An error message can name a macro that you did not intend. The reported errors come from the candidate with the fewest errors, and that candidate is not always the one that you had in mind. Read the errors together with the bodies below, and start from the argument types of your call.
Each entry below states which collection operators its body calls, and each heading carries the source line, so two entries with one name stay apart.
The macros
Section titled “The macros”Print (x) — line 17
Section titled “Print (x) — line 17”defn Print (x) (print '' + x)Definition: lib/stdops.rgr, line 17.
Print (x) — line 18
Section titled “Print (x) — line 18”defn Print (x) (print x)Definition: lib/stdops.rgr, line 18.
Range (from to)
Section titled “Range (from to)”defn Range (from to) { def res:[int] def f from while ( f < to ) { push res f f = f + 1 } ret res}Definition: lib/stdops.rgr, line 20.
ForEach (list f) — reads an array, line 31
Section titled “ForEach (list f) — reads an array, line 31”The body reads the argument with at, size.
defn ForEach (list f) { def cnt (size list) def i 0 while(i < cnt) { f (at list i) i = i + 1 }}Definition: lib/stdops.rgr, line 31.
Compose (f1 f2)
Section titled “Compose (f1 f2)”defn Compose (f1 f2) (fn:? (x:?) { return (f1 ( (f2 (x) ) ) )})Definition: lib/stdops.rgr, line 41.
Map (list f)
Section titled “Map (list f)”The body reads the argument with at, size.
defn Map ( list f ) { def cnt (size list) def res:[?] def i 0 while(i < cnt) { def myItem (at list i) def item ( f myItem ) push res item i = i + 1 } ret res}Definition: lib/stdops.rgr, line 45.
Reduce (list theFn initial)
Section titled “Reduce (list theFn initial)”The body reads the argument with at, size.
defn Reduce ( list theFn initial) { def cnt (size list) def acc@(weak temp) initial def i 0 while (i < cnt) { def myItem (at list i) acc = ( theFn acc myItem ) i = i + 1 } ret acc}Definition: lib/stdops.rgr, line 58.
Reduce (list2 theFn initial)
Section titled “Reduce (list2 theFn initial)”The body reads the argument with at, size.
defn Reduce ( list2 theFn initial) { def cnt (size list2) def acc@(weak temp) initial def i 0 while (i < cnt) { def myItem (at list2 i) acc = ( theFn (acc myItem ) ) i = i + 1 } ret acc}Definition: lib/stdops.rgr, line 70.
Filter (list f) — reads an array, line 82
Section titled “Filter (list f) — reads an array, line 82”The body reads the argument with at, size.
defn Filter ( list f ) { def cnt (size list) def res:[?] def i 0 while(i < cnt) { def myItem (at list i) if( f myItem ) { push res myItem } i = i + 1 } ret res}Definition: lib/stdops.rgr, line 82.
Filter (list f) — reads an array, line 96
Section titled “Filter (list f) — reads an array, line 96”The body reads the argument with at, size.
defn Filter ( list f ) { def cnt (size list) def res:[?] def i 0 while(i < cnt) { def myItem (at list i) if( f (myItem ) ) { push res myItem } i = i + 1 } ret res}Definition: lib/stdops.rgr, line 96.
Revert (list)
Section titled “Revert (list)”The body reads the argument with at, size.
defn Revert (list) { def cnt (size list) def i 0 def end (cnt - 1) def res (clone list) while(i < end) { def v1 (at list i) def v2 (at list end) set res end v1 set res i v2 i = i + 1 end = end - 1 } ret res}Definition: lib/stdops.rgr, line 110.
ForEach (list f) — reads an array, line 127
Section titled “ForEach (list f) — reads an array, line 127”The body reads the argument with at, size.
defn ForEach (list f) { def cnt (size list) def i 0 while(i < cnt) { f ( (at list i) ) i = i + 1 }}Definition: lib/stdops.rgr, line 127.
ForEach (list f) — reads a hash map
Section titled “ForEach (list f) — reads a hash map”The body reads the argument with keys, get, at, size, unwrap.
defn ForEach (list f) { def keyList (keys list) def cnt (size keyList) def i 0 while(i < cnt) { def k (at keyList i) f (unwrap (get list k)) i = i + 1 }}Definition: lib/stdops.rgr, line 136.
ConCat (left right)
Section titled “ConCat (left right)”defn ConCat (left right) { def results:[Any] forEach left { def tmp@(temp) item push results tmp } forEach right { def tmp@(temp) item push results tmp } ret results}Definition: lib/stdops.rgr, line 147.
ShowAny (anyItem)
Section titled “ShowAny (anyItem)”defn ShowAny (anyItem) { case anyItem str:string { print 'string: ' + str } case anyItem i:int { print " int : " + i } case anyItem b:boolean { print " boolean : " + (? b 'true' 'false') }}Definition: lib/stdops.rgr, line 160.
Ranger 3.5.1 · commit f323fd4 · development build