summaryrefslogtreecommitdiff
path: root/parser
diff options
context:
space:
mode:
authorMarc Vertes <mvertes@free.fr>2023-11-13 09:34:56 +0100
committerMarc Vertes <mvertes@free.fr>2023-11-13 09:34:56 +0100
commit2eab5877e1c634db872b595dd2414f4031ae4eb5 (patch)
tree66cf2f71f0e449ee629d684b4f9fe30d7bf1d61f /parser
parent1977ce7c976cbbd5bd0de1d479a0abe269e62f3d (diff)
parser: initial support for type declarations.
The parsing logic for type declarations is there. Note that no tokens are produced, only symbols. The different type kinds will be added next.
Diffstat (limited to 'parser')
-rw-r--r--parser/README.md2
-rw-r--r--parser/decl.go42
-rw-r--r--parser/interpreter_test.go11
-rw-r--r--parser/parse.go4
-rw-r--r--parser/type.go31
5 files changed, 72 insertions, 18 deletions
diff --git a/parser/README.md b/parser/README.md
index ecb7c41..54fead3 100644
--- a/parser/README.md
+++ b/parser/README.md
@@ -52,7 +52,7 @@ Go language support:
- [x] var defined by assign :=
- [x] var assign =
- [x] var declaration
-- [ ] type declaration
+- [x] type declaration
- [x] func declaration
- [ ] const declaration
- [ ] iota expression
diff --git a/parser/decl.go b/parser/decl.go
index fa07c17..6c10363 100644
--- a/parser/decl.go
+++ b/parser/decl.go
@@ -9,8 +9,48 @@ import (
"github.com/gnolang/parscan/scanner"
)
+func (p *Parser) ParseType(in Tokens) (out Tokens, err error) {
+ if len(in) < 2 {
+ return out, missingTypeError
+ }
+ if in[1].Id != lang.ParenBlock {
+ return p.parseTypeLine(in[1:])
+ }
+ if in, err = p.Scan(in[1].Block(), false); err != nil {
+ return out, err
+ }
+ for _, lt := range in.Split(lang.Semicolon) {
+ ot, err := p.parseTypeLine(lt)
+ if err != nil {
+ return out, err
+ }
+ out = append(out, ot...)
+ }
+ return out, err
+}
+
+func (p *Parser) parseTypeLine(in Tokens) (out Tokens, err error) {
+ if len(in) < 2 {
+ return out, missingTypeError
+ }
+ if in[0].Id != lang.Ident {
+ return out, errors.New("not an ident")
+ }
+ isAlias := in[1].Id == lang.Assign
+ toks := in[1:]
+ if isAlias {
+ toks = toks[1:]
+ }
+ typ, err := p.ParseTypeExpr(toks)
+ if err != nil {
+ return out, err
+ }
+ p.addSym(unsetAddr, in[0].Str, nil, symType, typ, p.funcScope != "")
+ return out, err
+}
+
func (p *Parser) ParseVar(in Tokens) (out Tokens, err error) {
- if len(in) < 1 {
+ if len(in) < 2 {
return out, errors.New("missing expression")
}
if in[1].Id != lang.ParenBlock {
diff --git a/parser/interpreter_test.go b/parser/interpreter_test.go
index edb6b0d..3a5598e 100644
--- a/parser/interpreter_test.go
+++ b/parser/interpreter_test.go
@@ -164,6 +164,17 @@ func TestSwitch(t *testing.T) {
})
}
+func TestType(t *testing.T) {
+ 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"},
+ })
+}
+
func TestVar(t *testing.T) {
run(t, []etest{
{src: "var a int; a", res: "0"},
diff --git a/parser/parse.go b/parser/parse.go
index a7675b4..7de73b6 100644
--- a/parser/parse.go
+++ b/parser/parse.go
@@ -87,6 +87,8 @@ func (p *Parser) ParseStmt(in Tokens) (out Tokens, err error) {
return p.ParseReturn(in)
case lang.Switch:
return p.ParseSwitch(in)
+ case lang.Type:
+ return p.ParseType(in)
case lang.Var:
return p.ParseVar(in)
case lang.Ident:
@@ -226,7 +228,7 @@ func (p *Parser) ParseFunc(in Tokens) (out Tokens, err error) {
if bi < 0 {
return out, fmt.Errorf("no function body")
}
- typ, err := p.ParseType(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 00aedc8..41bcfe1 100644
--- a/parser/type.go
+++ b/parser/type.go
@@ -3,17 +3,28 @@ package parser
import (
"errors"
"fmt"
- "log"
"reflect"
"strings"
"github.com/gnolang/parscan/lang"
)
-// ParseType parses a list of tokens defining a type expresssion and returns
+type typeFlag int
+
+const (
+ parseTypeIn typeFlag = iota
+ parseTypeOut
+ parseTypeVar
+ parseTypeType
+)
+
+var (
+ missingTypeError = errors.New("Missing type")
+)
+
+// ParseTypeExpr parses a list of tokens defining a type expresssion and returns
// the corresponding runtime type or an error.
-func (p *Parser) ParseType(in Tokens) (typ reflect.Type, err error) {
- log.Println("ParseType", in)
+func (p *Parser) ParseTypeExpr(in Tokens) (typ reflect.Type, err error) {
switch in[0].Id {
case lang.Func:
// Get argument and return token positions depending on function pattern:
@@ -65,16 +76,6 @@ func (p *Parser) ParseType(in Tokens) (typ reflect.Type, err error) {
return typ, err
}
-type typeFlag int
-
-const (
- parseTypeIn typeFlag = iota
- parseTypeOut
- parseTypeVar
-)
-
-var missingTypeError = errors.New("Missing type")
-
// parseParamTypes parses a list of comma separated typed parameters and returns a list of
// runtime types. Implicit parameter names and types are supported.
func (p *Parser) parseParamTypes(in Tokens, flag typeFlag) (types []reflect.Type, vars []string, err error) {
@@ -101,7 +102,7 @@ func (p *Parser) parseParamTypes(in Tokens, flag typeFlag) (types []reflect.Type
continue
}
}
- typ, err := p.ParseType(t)
+ typ, err := p.ParseTypeExpr(t)
if err != nil {
return nil, nil, err
}