token: add Type enum, Token struct, and String() method
diff --git a/token/token.go b/token/token.go
new file mode 100644
index 0000000..d50eb36
--- /dev/null
+++ b/token/token.go
@@ -0,0 +1,48 @@
+package token
+
+import "fmt"
+
+// Type represents the type of a lexical token.
+type Type int
+
+const (
+ Number Type = iota // numeric literal
+ Plus // +
+ Minus // -
+ Star // *
+ Slash // /
+ LParen // (
+ RParen // )
+ EOF // end of input
+)
+
+// String returns a human-readable name for the token type.
+func (t Type) String() string {
+ switch t {
+ case Number:
+ return "Number"
+ case Plus:
+ return "+"
+ case Minus:
+ return "-"
+ case Star:
+ return "*"
+ case Slash:
+ return "/"
+ case LParen:
+ return "("
+ case RParen:
+ return ")"
+ case EOF:
+ return "EOF"
+ default:
+ return fmt.Sprintf("Unknown(%d)", int(t))
+ }
+}
+
+// Token represents a single lexical token.
+type Token struct {
+ Type Type // the kind of token
+ Literal string // raw text (e.g. "3.14", "+")
+ Pos int // byte offset in input string
+}
diff --git a/token/token_test.go b/token/token_test.go
new file mode 100644
index 0000000..05045b0
--- /dev/null
+++ b/token/token_test.go
@@ -0,0 +1,25 @@
+package token
+
+import "testing"
+
+func TestTypeString(t *testing.T) {
+ tests := []struct {
+ typ Type
+ want string
+ }{
+ {Number, "Number"},
+ {Plus, "+"},
+ {Minus, "-"},
+ {Star, "*"},
+ {Slash, "/"},
+ {LParen, "("},
+ {RParen, ")"},
+ {EOF, "EOF"},
+ {Type(99), "Unknown(99)"},
+ }
+ for _, tc := range tests {
+ if got := tc.typ.String(); got != tc.want {
+ t.Errorf("Type(%d).String() = %q, want %q", int(tc.typ), got, tc.want)
+ }
+ }
+}