diff options
| author | Marc Vertes <mvertes@free.fr> | 2023-11-15 22:38:46 +0100 |
|---|---|---|
| committer | Marc Vertes <mvertes@free.fr> | 2023-11-15 22:38:46 +0100 |
| commit | a79e558d825c5b777c95c5e098b01391ee36781e (patch) | |
| tree | 977e5131eee46197a6e72377a168df23ca356948 | |
| parent | a4d7fb2da6a8390b818dae8d07391c7d76e365e9 (diff) | |
parser: parse struct type declarations
Recursive structs and embedded structs are not supported yet.
| -rw-r--r-- | lang/golang/go.go | 2 | ||||
| -rw-r--r-- | parser/README.md | 2 | ||||
| -rw-r--r-- | parser/decl.go | 8 | ||||
| -rw-r--r-- | parser/expr.go | 2 | ||||
| -rw-r--r-- | parser/interpreter_test.go | 12 | ||||
| -rw-r--r-- | parser/type.go | 32 |
6 files changed, 45 insertions, 13 deletions
diff --git a/lang/golang/go.go b/lang/golang/go.go index 44cbd3a..26af4f3 100644 --- a/lang/golang/go.go +++ b/lang/golang/go.go @@ -74,6 +74,8 @@ var GoSpec = &lang.Spec{ "*": {TokenId: lang.Mul, Precedence: 1}, "/": {TokenId: lang.Quo, Precedence: 1}, "%": {TokenId: lang.Rem, Precedence: 1}, + "<<": {TokenId: lang.Shl, Precedence: 1}, + ">>": {TokenId: lang.Shr, Precedence: 1}, "+": {TokenId: lang.Add, Precedence: 2}, "-": {TokenId: lang.Sub, Precedence: 2}, "=": {TokenId: lang.Assign, Precedence: 6}, diff --git a/parser/README.md b/parser/README.md index 6f3b6dd..3fbbf61 100644 --- a/parser/README.md +++ b/parser/README.md @@ -40,7 +40,7 @@ Go language support: - [x] function types - [ ] variadic functions - [ ] pointers -- [ ] structures +- [x] structures - [ ] embedded structures - [ ] recursive structures - [ ] interfaces diff --git a/parser/decl.go b/parser/decl.go index ba68da0..782b57a 100644 --- a/parser/decl.go +++ b/parser/decl.go @@ -48,7 +48,7 @@ func (p *Parser) parseConstLine(in Tokens) (out Tokens, err error) { } var vars []string if _, vars, err = p.parseParamTypes(decl, parseTypeVar); err != nil { - if errors.Is(err, missingTypeError) { + if errors.Is(err, MissingTypeErr) { for _, lt := range decl.Split(lang.Comma) { vars = append(vars, lt[0].Str) // TODO: compute type from rhs @@ -188,7 +188,7 @@ var gotok = map[lang.TokenId]token.Token{ func (p *Parser) ParseType(in Tokens) (out Tokens, err error) { if len(in) < 2 { - return out, missingTypeError + return out, MissingTypeErr } if in[1].Id != lang.ParenBlock { return p.parseTypeLine(in[1:]) @@ -208,7 +208,7 @@ func (p *Parser) ParseType(in Tokens) (out Tokens, err error) { func (p *Parser) parseTypeLine(in Tokens) (out Tokens, err error) { if len(in) < 2 { - return out, missingTypeError + return out, MissingTypeErr } if in[0].Id != lang.Ident { return out, errors.New("not an ident") @@ -254,7 +254,7 @@ func (p *Parser) parseVarLine(in Tokens) (out Tokens, err error) { } var vars []string if _, vars, err = p.parseParamTypes(decl, parseTypeVar); err != nil { - if errors.Is(err, missingTypeError) { + if errors.Is(err, MissingTypeErr) { for _, lt := range decl.Split(lang.Comma) { vars = append(vars, lt[0].Str) // TODO: compute type from rhs diff --git a/parser/expr.go b/parser/expr.go index d626e9e..2cd19c6 100644 --- a/parser/expr.go +++ b/parser/expr.go @@ -34,7 +34,7 @@ func (p *Parser) ParseExpr(in Tokens) (out Tokens, err error) { case lang.Int, lang.String: out = append(out, t) vl++ - case lang.Define, lang.Add, lang.Sub, lang.Assign, lang.Equal, lang.Greater, lang.Less, lang.Mul, lang.Land, lang.Lor: + case lang.Define, lang.Add, lang.Sub, lang.Assign, lang.Equal, lang.Greater, lang.Less, lang.Mul, lang.Land, lang.Lor, lang.Shl, lang.Shr: if vl < 2 { ops = append(ops, t) break diff --git a/parser/interpreter_test.go b/parser/interpreter_test.go index 7ac1212..ac8dfc4 100644 --- a/parser/interpreter_test.go +++ b/parser/interpreter_test.go @@ -174,19 +174,23 @@ func TestConst(t *testing.T) { run(t, []etest{ {src: "const a = 1+2; a", res: "3"}, {src: "const a, b = 1, 2; a+b", res: "3"}, + {src: "const huge = 1 << 100; const four = huge >> 98; four", res: "4"}, {src: src0 + "c", res: "2"}, }) } func TestType(t *testing.T) { + src0 := `type( + I int + S string +) +` run(t, []etest{ {src: "type t int; var a t = 1; a", res: "1"}, {src: "type t = int; var a t = 1; a", res: "1"}, - {src: `type ( - I int - S string -); var s S = "xx"; s`, res: "xx"}, + {src: src0 + `var s S = "xx"; s`, res: "xx"}, + {src: "type T struct {a string; b, c int}; var t T; t", res: "{ 0 0}"}, }) } diff --git a/parser/type.go b/parser/type.go index 41bcfe1..f39acea 100644 --- a/parser/type.go +++ b/parser/type.go @@ -19,7 +19,10 @@ const ( ) var ( - missingTypeError = errors.New("Missing type") + InvalidTypeErr = errors.New("invalid type") + MissingTypeErr = errors.New("missing type") + SyntaxErr = errors.New("syntax error") + TypeNotImplementedErr = errors.New("not implemented") ) // ParseTypeExpr parses a list of tokens defining a type expresssion and returns @@ -69,9 +72,32 @@ func (p *Parser) ParseTypeExpr(in Tokens) (typ reflect.Type, err error) { // TODO: selector expression (pkg.type) s, _, ok := p.getSym(in[0].Str, p.scope) if !ok || s.kind != symType { - return nil, fmt.Errorf("invalid type %s", in[0].Str) + return nil, fmt.Errorf("%w: %s", InvalidTypeErr, in[0].Str) } return s.Type, nil + + case lang.Struct: + if len(in) != 2 || in[1].Id != lang.BraceBlock { + return nil, fmt.Errorf("%w: %v", SyntaxErr, in) + } + if in, err = p.Scan(in[1].Block(), false); err != nil { + return nil, err + } + var fields []reflect.StructField + for _, lt := range in.Split(lang.Semicolon) { + types, names, err := p.parseParamTypes(lt, parseTypeType) + if err != nil { + return nil, err + } + for i, name := range names { + fields = append(fields, reflect.StructField{Name: "X" + name, Type: types[i]}) + // TODO: handle embedded fields + } + } + return reflect.StructOf(fields), nil + + default: + return nil, fmt.Errorf("%w: %v", TypeNotImplementedErr, in[0].Name()) } return typ, err } @@ -93,7 +119,7 @@ func (p *Parser) parseParamTypes(in Tokens, flag typeFlag) (types []reflect.Type t = t[1:] if len(t) == 0 { if len(types) == 0 { - return nil, nil, missingTypeError + return nil, nil, MissingTypeErr } // Type was ommitted, apply the previous one from the right. types = append([]reflect.Type{types[0]}, types...) |
