summaryrefslogtreecommitdiff
path: root/parser
diff options
context:
space:
mode:
authorMarc Vertes <mvertes@free.fr>2024-04-23 14:36:57 +0200
committerGitHub <noreply@github.com>2024-04-23 14:36:57 +0200
commit0063922f5c8a07b78603b2da7f6a3c2094711c3d (patch)
tree613cd8f53e86f33678a2f96fa0e776edfa555101 /parser
parent1bff92c52b27b9a516599e172fe9852c3d99be38 (diff)
feat: initial and partial support of composite expressions (#9)
A new `Composite` token is created. Literal composite expressions are recognized and partially handled by the parser but not yet by the code generator. Other cosmetic changes are present.
Diffstat (limited to 'parser')
-rw-r--r--parser/compiler.go3
-rw-r--r--parser/decl.go3
-rw-r--r--parser/expr.go25
-rw-r--r--parser/interpreter_test.go8
-rw-r--r--parser/parse.go4
-rw-r--r--parser/type.go24
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
+}