diff options
Diffstat (limited to 'parser')
| -rw-r--r-- | parser/compiler.go | 3 | ||||
| -rw-r--r-- | parser/decl.go | 3 | ||||
| -rw-r--r-- | parser/expr.go | 25 | ||||
| -rw-r--r-- | parser/interpreter_test.go | 8 | ||||
| -rw-r--r-- | parser/parse.go | 4 | ||||
| -rw-r--r-- | parser/type.go | 24 |
6 files changed, 55 insertions, 12 deletions
diff --git a/parser/compiler.go b/parser/compiler.go index 7a90597..3b9a32d 100644 --- a/parser/compiler.go +++ b/parser/compiler.go @@ -134,6 +134,9 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { } emit(int64(t.Pos), vm.CallX, int64(t.Beg)) + case lang.Composite: + log.Println("COMPOSITE") + case lang.Grow: emit(int64(t.Pos), vm.Grow, int64(t.Beg)) diff --git a/parser/decl.go b/parser/decl.go index b1cd13b..23b5ed6 100644 --- a/parser/decl.go +++ b/parser/decl.go @@ -280,10 +280,11 @@ func (p *Parser) parseTypeLine(in Tokens) (out Tokens, err error) { if isAlias { toks = toks[1:] } - typ, err := p.ParseTypeExpr(toks) + typ, err := p.parseTypeExpr(toks) if err != nil { return out, err } + typ.Name = in[0].Str p.addSym(unsetAddr, in[0].Str, vm.NewValue(typ), symType, typ, p.funcScope != "") return out, err } diff --git a/parser/expr.go b/parser/expr.go index 9e96e42..cf6ee74 100644 --- a/parser/expr.go +++ b/parser/expr.go @@ -7,10 +7,11 @@ import ( "github.com/mvertes/parscan/lang" "github.com/mvertes/parscan/scanner" + "github.com/mvertes/parscan/vm" ) func (p *Parser) parseExpr(in Tokens) (out Tokens, err error) { - log.Println("ParseExpr in:", in) + log.Println("parseExpr in:", in) var ops, selectors Tokens var vl int var selectorIndex string @@ -84,6 +85,24 @@ func (p *Parser) parseExpr(in Tokens) (out Tokens, err error) { out = append(out, t) vl++ ops = append(ops, scanner.Token{Tok: lang.Call, Pos: t.Pos, Beg: p.numItems(t.Block(), lang.Comma)}) + case lang.BraceBlock: + // the block can be a func body or a composite type content. + // In both cases it is preceded by a type definition. We must determine the starting token of type def, + // parse the type def, and substitute the type def by a single ident. + // TODO: handle implicit type in composite expression. + ti := p.typeStartIndex(in[:len(in)-1]) + if ti == -1 { + return out, ErrInvalidType + } + typ, err := p.parseTypeExpr(in[ti : len(in)-1]) + if err != nil { + return out, ErrInvalidType + } + p.addSym(unsetAddr, typ.String(), vm.NewValue(typ), symType, typ, p.funcScope != "") + out = append(out, t, scanner.Token{Tok: lang.Ident, Pos: t.Pos, Str: typ.String()}) + i = ti + vl += 2 + ops = append(ops, scanner.Token{Tok: lang.Composite, Pos: t.Pos}) case lang.BracketBlock: out = append(out, t) vl++ @@ -113,7 +132,7 @@ func (p *Parser) parseExpr(in Tokens) (out Tokens, err error) { } out = append(out, ops...) - log.Println("ParseExpr out:", out, "vl:", vl, "ops:", ops) + log.Println("parseExpr out:", out, "vl:", vl, "ops:", ops) // A logical operator (&&, ||) involves additional control flow operations. if out, err = p.parseLogical(out); err != nil { return out, err @@ -133,7 +152,7 @@ func (p *Parser) parseExpr(in Tokens) (out Tokens, err error) { t := out[i] var toks Tokens switch t.Tok { - case lang.ParenBlock, lang.BracketBlock: + case lang.ParenBlock, lang.BracketBlock, lang.BraceBlock: if toks, err = p.parseExprStr(t.Block()); err != nil { return out, err } diff --git a/parser/interpreter_test.go b/parser/interpreter_test.go index a459359..a6ad246 100644 --- a/parser/interpreter_test.go +++ b/parser/interpreter_test.go @@ -255,3 +255,11 @@ func TestImport(t *testing.T) { {src: `import . "fmt"; Println(4)`, res: "<nil>"}, }) } + +func TestComposite(t *testing.T) { + run(t, []etest{ + {src: "type T struct{}; t := T{}; t", res: "{}"}, + {src: "t := struct{}{}; t", res: "{}"}, + // {src: "type T struct{N int}; t := T{2}; t", res: "{2}"}, + }) +} diff --git a/parser/parse.go b/parser/parse.go index bd19d81..add1600 100644 --- a/parser/parse.go +++ b/parser/parse.go @@ -74,7 +74,7 @@ func (p *Parser) parseStmt(in Tokens) (out Tokens, err error) { if len(in) == 0 { return nil, nil } - log.Println("ParseStmt in:", in) + log.Println("parseStmt in:", in) switch t := in[0]; t.Tok { case lang.Break: return p.parseBreak(in) @@ -249,7 +249,7 @@ func (p *Parser) parseFunc(in Tokens) (out Tokens, err error) { if bi < 0 { return out, fmt.Errorf("no function body") } - typ, err := p.ParseTypeExpr(in[:bi]) + typ, err := p.parseTypeExpr(in[:bi]) if err != nil { return out, err } diff --git a/parser/type.go b/parser/type.go index b9ab0f9..ba60e8f 100644 --- a/parser/type.go +++ b/parser/type.go @@ -26,12 +26,10 @@ var ( ErrTypeNotImplemented = errors.New("not implemented") ) -// ParseTypeExpr parses a list of tokens defining a type expresssion and returns -// the corresponding runtime type or an error. -func (p *Parser) ParseTypeExpr(in Tokens) (typ *vm.Type, err error) { +func (p *Parser) parseTypeExpr(in Tokens) (typ *vm.Type, err error) { switch in[0].Tok { case lang.BracketBlock: - typ, err := p.ParseTypeExpr(in[1:]) + typ, err := p.parseTypeExpr(in[1:]) if err != nil { return nil, err } @@ -53,7 +51,7 @@ func (p *Parser) ParseTypeExpr(in Tokens) (typ *vm.Type, err error) { return vm.SliceOf(typ), nil case lang.Mul: - typ, err := p.ParseTypeExpr(in[1:]) + typ, err := p.parseTypeExpr(in[1:]) if err != nil { return nil, err } @@ -157,7 +155,7 @@ func (p *Parser) parseParamTypes(in Tokens, flag typeFlag) (types []*vm.Type, va continue } } - typ, err := p.ParseTypeExpr(t) + typ, err := p.parseTypeExpr(t) if err != nil { return nil, nil, err } @@ -196,3 +194,17 @@ func (p *Parser) hasFirstParam(in Tokens) bool { s, _, ok := p.getSym(in[0].Str, p.scope) return !ok || s.kind != symType } + +// typeStartIndex returns the index of the start of type expression in tokens, or -1. +func (p *Parser) typeStartIndex(in Tokens) int { + index := len(in) - 1 + for i := index; i >= 0; i-- { + switch in[i].Tok { + case lang.Ident, lang.Struct, lang.Map, lang.Func, lang.Interface, lang.Mul, lang.BraceBlock, lang.BracketBlock, lang.ParenBlock: + index = i + default: + return index + } + } + return -1 +} |
