What I am trying to do is add a third argument to make(map...), where it will use that argument to make compile-time modifications when it substitutes it into makemap (and whatever else) later on. I.E...
make(map[string]int, 1024, TREE)
Where TREE is a constant defined used to specify we want to have a tree map instead of a normal hash map. Imagine if the above map declaration was used to print occurrences of words in alphabetical order, I.E
"A: 23"
"An: 4"
"Bee: 2"
"C++: 1"
A poor example, I know, but imagine if there were a LARGE number of words (as in it scans a HUGE document) and wanted to handle this. A normal hash map would be inefficient (because it's not ordered) while a tree would be very efficient (as we just traverse each node in the tree). No extra space or time to sort each value, etc. One could suggest that, of course, they create their own map, which they could, certainly, but adding a built-in one would be very beneficial as well. At the very least, it'll be a good experiment for me even if it is a rejected suggestion...
Now on to the main issue... In 'cmd/compile/internal/gc/typecheck.go', I have modified the specific OMAKE->TMAP portion to consume the third argument if it exists, otherwise just placing a default value of 0 for the Right child. Mine quite literally copies how it acquires the first argument (capacity/size), hence I do not think there should be an issue.
case TMAP:
if i < len(args) {
l = args[i]
i++
l = typecheck(l, Erv)
l = defaultlit(l, Types[TINT])
if l.Type == nil {
n.Type = nil
return n
}
if !checkmake(t, "size", l) {
n.Type = nil
return n
}
n.Left = l
// L.J: Code added for 3rd parameter, 'mode'
if i < len(args) {
right := args[i]
i++
right = typecheck(right, Erv)
right = defaultlit(right, Types[TINT])
if right.Type == nil {
n.Type = nil
return n
}
if !checkmake(t, "mode", right) {
n.Type = nil
return n
}
n.Right = right
}
} else {
n.Left = Nodintconst(0)
n.Right = Nodintconst(0)
}
n.Op = OMAKEMAP
As it can be see, it consumes the argument (advances the index, i), typechecks, etc. If it does not exist, it just becomes a int constant of 0 to symbolize it does not exist.
Next, while it walks the tree, in 'cmd/compile/internal/gc/walk.go', I explicitly check for the Right child, however I've had some issues. Even though it SHOULD always be present, it seems that the Right node becomes nil somewhere along the line, hence I need to explicitly check for if n.Right isn't nil to prevent nil-pointer dereference runtime errors. However, once again, I have no idea WHY this is the case, as it explicitly gets set in typecheck.go.
case OMAKEMAP:
t := n.Type
a := nodnil() // hmap buffer
r := nodnil() // bucket buffer
if n.Esc == EscNone {
// Allocate hmap buffer on stack.
var_ := temp(hmap(t))
a = Nod(OAS, var_, nil) // zero temp
a = typecheck(a, Etop)
init.Append(a)
a = Nod(OADDR, var_, nil)
// Allocate one bucket on stack.
// Maximum key/value size is 128 bytes, larger objects
// are stored with an indirection. So max bucket size is 2048+eps.
var_ = temp(mapbucket(t))
r = Nod(OAS, var_, nil) // zero temp
r = typecheck(r, Etop)
init.Append(r)
r = Nod(OADDR, var_, nil)
}
// L.J: Only change in code
if n.Right != nil && n.Right.Int64() != 0 {
Yyerror("Mode given: %v", n.Right.E)
}
fn := syslook("makemap")
fn = substArgTypes(fn, hmap(t), mapbucket(t), t.Key(), t.Val())
n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
Then, lastly, when i attempt to compile a program (and I have run all.bat and make.bat to create the go.exe and gofmt.exe executable, and I am using them to compile the test programs), it explicitly states that there are too many arguments to make(map...). I've searched for this error, and it only performs this check after the switch statement for case OMAKE, which only checks if there were more arguments supplied than were consumed (hence my confusion).
if i < len(args) {
Yyerror("too many arguments to make(%v)", t)
n.Op = OMAKE
n.Type = nil
return n
}
The above seems to be the culprit, but once again I explicitly consume the argument by advancing the index, i. I am very confused... Can someone help explain why this is? Is there another check for the amount of arguments to make(...)?