goccmack / gocc

Parser / Scanner Generator
Other
622 stars 48 forks source link

Make typeMap/idMap publicly accessible #92

Open Happy-Ferret opened 5 years ago

Happy-Ferret commented 5 years ago

Curious.

Any good reason against making typeMap and idMap public, so its contents can be accessed by the consumer?

I've spent the past 6 hours trying to painfully retrieve a Type's index from idMap through reflection, and I'm still not close to a solution.

If it was IdMap instead, one could simply loop over it and retrieve the index like so:

    for i, k := range token.TokMap.IdMap {
        switch k {
        case intLit.Type:
            fmt.Println(i)
        }
    }
awalterschulze commented 5 years ago

What do you want to use it for?

On Tue, 2 Jul 2019 at 07:29, Happy-Ferret notifications@github.com wrote:

Curious.

Any good reason against making typeMap https://github.com/goccmack/gocc/blob/master/internal/token/gen/golang/token.go#L90 and idMap public, so its contents can be accessed by the consumer?

I've spent the past 6 hours trying to painfully retrieve a Type's index from idMap through reflection, and I'm still not close to a solution.

If it was IdMap instead, one could simply loop over it and retrieve the index like so:

for i, k := range token.TokMap.IdMap { switch k { case intLit.Type: fmt.Println(i) } }

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/goccmack/gocc/issues/92?email_source=notifications&email_token=AAN6YLL4ZKIUNPCCNWRHRNTP5LYTNA5CNFSM4H4YOEHKYY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4G4ZQFPA, or mute the thread https://github.com/notifications/unsubscribe-auth/AAN6YLPX2ZBVPX7CKWILRW3P5LYTNANCNFSM4H4YOEHA .

Happy-Ferret commented 5 years ago

NVM. After some head scratching it turned out to be much easier than I had thought.

t := reflect.ValueOf(token.TokMap)
v := t.FieldByName("typeMap").Index(int(intLit.Type))

// Prints integer type
println(v)

I'm in the process of writing a small language compiler and needed that information for the debug output.

Here's the full -- quick and dirty. I'm, obviously, going to make it generic for types other than int32 -- implementation of catching an overflow (message is my own package for outputting compiler errors. I didn't like the verbose output of the gocc generated errors package):

func NewIntegerLiteral(integer Attrib) (Expression, error) {
    intLit, ok := integer.(*token.Token)
    if !ok {
        return nil, Error("NewIntegerLiteral", "*token.Token", "integer", integer)
    }

    maxInt := 0x7fffffff
    minInt := -0x80000000
    number, _ := strconv.Atoi(string(intLit.Lit))

    if number > maxInt || number < minInt {
        t := reflect.ValueOf(token.TokMap)
        v := t.FieldByName("typeMap").Index(int(intLit.Type))

        message.Errorf("Arithmetic overflow detected! %v overflows %v (Line: %v, Column: %v)", number, v, intLit.Pos.Line, intLit.Pos.Column)
    }

    return &IntegerLiteral{Token: intLit, Value: string(intLit.Lit)}, nil
}
awalterschulze commented 5 years ago

Very interesting.

Why print out the error, instead of returning it?

Warning: I don’t know if FieldByName works for private fields for all versions of Go.

On Tue, 2 Jul 2019 at 08:30, Happy-Ferret notifications@github.com wrote:

NVM. After some head scratching it turned out to be much easier than I had thought.

t := reflect.ValueOf(token.TokMap)v := t.FieldByName("typeMap").Index(int(intLit.Type)) // Prints integer typeprintln(v)

I'm in the process of writing a small language compiler and needed that information for the debug output.

Here's the full -- quick and dirty. I'm, obviously, going to make it generic for types other than int32 -- implementation of catching an overflow (message is my own package for outputting compiler errors. I didn't like the verbose output of the gocc generated errors package):

func NewIntegerLiteral(integer Attrib) (Expression, error) { intLit, ok := integer.(token.Token) if !ok { return nil, Error("NewIntegerLiteral", "token.Token", "integer", integer) }

maxInt := 0x7fffffff minInt := -0x80000000 number, _ := strconv.Atoi(string(intLit.Lit))

if number > maxInt || number < minInt { t := reflect.ValueOf(token.TokMap) v := t.FieldByName("typeMap").Index(int(intLit.Type))

  message.Errorf("Arithmetic overflow detected! %v overflows %v (Line: %v, Column: %v)", number, v, intLit.Pos.Line, intLit.Pos.Column)

}

return &IntegerLiteral{Token: intLit, Value: string(intLit.Lit)}, nil }

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/goccmack/gocc/issues/92?email_source=notifications&email_token=AAN6YLMZHPIPFJSYBERI64LP5L7Z7A5CNFSM4H4YOEHKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODZALFOI#issuecomment-507556537, or mute the thread https://github.com/notifications/unsubscribe-auth/AAN6YLPPCR4ZW4L6LEPQ4ZLP5L7Z7ANCNFSM4H4YOEHA .

Happy-Ferret commented 5 years ago

Why print out the error, instead of returning it?

Admittedly, because this project makes me feel like an utter newbie.

If I simply return the error with fmt.Errorf, the output is formatted to: ERROR Error in S21: sub(15,-), Pos(offset=284, line=14, column=21): Arithmetic overflow detected! -2147483649 overflows int (Line: 14, Column: 9)

So my message package looks like this instead:

package message

import (
    "fmt"
    "os"

    colorable "github.com/mattn/go-colorable"
    "github.com/sirupsen/logrus"
)

func init() {
    timestampFormat := "Mon Jan 2 15:04:05 -0700 MST 2006"
    var disableTimestamp bool

    if len(os.Getenv("TCTimestamp")) == 1 {
        disableTimestamp = false
    } else {
        disableTimestamp = true
    }
    logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true, DisableLevelTruncation: true, DisableTimestamp: disableTimestamp, FullTimestamp: true, TimestampFormat: timestampFormat})
    logrus.SetOutput(colorable.NewColorableStdout())
}

// Error throws an error and aborts the running process.
func Error(v interface{}) {
    logrus.Error(v)
    os.Exit(1)
}

// Errorf formats an error message according to a format specifier,
// throws the error and aborts the running process.
func Errorf(format string, v ...interface{}) {
    logrus.Error(fmt.Sprintf(format, v...))
    os.Exit(1)
}

// Warning displays a warning log message.
func Warning(v interface{}) {
    logrus.Warning(v)
}

// Info displays an informational log message.
func Info(v interface{}) {
    logrus.Info(v)
}
awalterschulze commented 5 years ago

You can still return the error log it after parsing, instead of logging it at the moment of the failure.