Skip to content

Commit

Permalink
support struct definition
Browse files Browse the repository at this point in the history
  • Loading branch information
hidetatz committed Aug 19, 2023
1 parent 0bd8cdc commit a9798ee
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 1 deletion.
19 changes: 19 additions & 0 deletions env.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ func (e *environment) delblockscope(mod *module) error {
return nil
}

func (e *environment) setstruct(mod *module, name string, s *structdef) error {
m, err := e.findmodule(mod)
if err != nil {
return err
}

m.setstruct(name, s)
return nil
}

func (e *environment) setobj(mod *module, name string, o *obj) error {
m, err := e.findmodule(mod)
if err != nil {
Expand All @@ -78,6 +88,15 @@ func (e *environment) setobj(mod *module, name string, o *obj) error {
return nil
}

func (e *environment) getstruct(mod *module, name string) (*structdef, bool) {
m, err := e.findmodule(mod)
if err != nil {
return nil, false
}

return m.getstruct(name)
}

func (e *environment) getobj(mod *module, name string) (*obj, bool) {
m, err := e.findmodule(mod)
if err != nil {
Expand Down
22 changes: 22 additions & 0 deletions mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,15 @@ func (m *module) setobj(name string, o *obj) {
m.globscope.setobj(name, o)
}

func (m *module) setstruct(name string, s *structdef) {
if m.funcscopes.Len() != 0 {
m.funcscopes.Back().Value.(*scope).setstruct(name, s)
return
}

m.globscope.setstruct(name, s)
}

func (m *module) getobj(name string) (*obj, bool) {
if m.funcscopes.Len() != 0 {
o, ok := m.funcscopes.Back().Value.(*scope).getobj(name)
Expand All @@ -184,6 +193,19 @@ func (m *module) getobj(name string) (*obj, bool) {
return m.globscope.getobj(name)
}

func (m *module) getstruct(name string) (*structdef, bool) {
if m.funcscopes.Len() != 0 {
s, ok := m.funcscopes.Back().Value.(*scope).getstruct(name)
if ok {
return s, true
}

return m.globscope.getglobstruct(name)
}

return m.globscope.getstruct(name)
}

func modtofile(modname string) string {
return modname + ".sb"
}
Expand Down
25 changes: 25 additions & 0 deletions node.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,31 @@ func (n *ndDict) String() string {
return sb.String()
}

type ndStruct struct {
tok *token
name node
vars []node
fns []node
}

func (n *ndStruct) token() *token { return n.tok }
func (n *ndStruct) String() string {
sb := strings.Builder{}
sb.WriteString("struct ")
sb.WriteString(n.name.String())
sb.WriteString("{\n")
for i := range n.vars {
sb.WriteString(" " + n.vars[i].String() + "\n")
}
sb.WriteString("---\n")
for i := range n.fns {
sb.WriteString(" " + n.fns[i].String() + "\n")
}
sb.WriteString("}")

return sb.String()
}

type ndContinue struct {
tok *token
}
Expand Down
45 changes: 45 additions & 0 deletions parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ func (p *parser) stmt() node {
return p.def()
}

if p.iscur(tkStruct) {
return p._struct()
}

if p.iscur(tkReturn) {
return p._return()
}
Expand Down Expand Up @@ -294,6 +298,47 @@ func (p *parser) def() node {
return n
}

// struct = "struct" ident "{" ident-list? def-list? "}"
func (p *parser) _struct() node {
p.skipnewline()
n := &ndStruct{tok: p.cur}
p.must(tkStruct)
n.name = p.ident()
p.must(tkLBrace)
p.skipnewline()

if p.iscur(tkRBrace) {
return n
}

// read variables
for {
if p.iscur(tkDef) {
break
}

if p.iscur(tkRBrace) {
break
}

n.vars = append(n.vars, p.ident())
p.skipnewline()
}

// read functions
for {
if p.iscur(tkRBrace) {
break
}

n.fns = append(n.fns, p.def())
p.skipnewline()
}

p.must(tkRBrace)
return n
}

// return = "return" expr
func (p *parser) _return() node {
p.skipnewline()
Expand Down
28 changes: 28 additions & 0 deletions process.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ func process(mod *module, nd node) (procResult, shibaErr) {
case *ndCondLoop:
return procCondLoop(mod, n)

case *ndStruct:
return procStruct(mod, n)

case *ndFunDef:
return procFunDef(mod, n)

Expand Down Expand Up @@ -467,6 +470,31 @@ func procCondLoop(mod *module, n *ndCondLoop) (procResult, shibaErr) {
return nil, nil
}

func procStruct(mod *module, n *ndStruct) (procResult, shibaErr) {
if _, ok := n.name.(*ndIdent); !ok {
return nil, &errSimple{msg: fmt.Sprintf("invalid struct name %s", n.name), l: n.token().loc}
}

name := n.name.(*ndIdent).ident
sd := &structdef{name: name}

for _, v := range n.vars {
if _, ok := v.(*ndIdent); !ok {
return nil, &errSimple{msg: fmt.Sprintf("invalid variable name %s in struct %s", v, name), l: n.token().loc}
}
sd.vars = append(sd.vars, v.(*ndIdent).ident)
}

for _, fn := range n.fns {
if _, err := process(mod, fn); err != nil {
return nil, err
}
}

env.setstruct(mod, name, sd)
return nil, nil
}

func procFunDef(mod *module, n *ndFunDef) (procResult, shibaErr) {
params := []string{}
for _, p := range n.params {
Expand Down
42 changes: 41 additions & 1 deletion scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import "container/list"

type scope struct {
objs map[string]*obj
structdefs map[string]*structdef
blockscopes *list.List
}

func newscope() *scope {
return &scope{
objs: map[string]*obj{},
structdefs: map[string]*structdef{},
blockscopes: list.New(),
}
}
Expand All @@ -22,6 +24,23 @@ func (s *scope) delblockscope() {
s.blockscopes.Remove(s.blockscopes.Back())
}

func (s *scope) setstruct(name string, sd *structdef) {
if s.blockscopes.Len() == 0 {
s.structdefs[name] = sd
return
}

for e := s.blockscopes.Back(); e != nil; e = e.Prev() {
bs := e.Value.(*blockscope)
if _, ok := bs.structdefs[name]; ok {
bs.structdefs[name] = sd
return
}
}

s.blockscopes.Back().Value.(*blockscope).structdefs[name] = sd
}

func (s *scope) setobj(name string, o *obj) {
if s.blockscopes.Len() == 0 {
s.objs[name] = o
Expand All @@ -39,6 +58,18 @@ func (s *scope) setobj(name string, o *obj) {
s.blockscopes.Back().Value.(*blockscope).objs[name] = o
}

func (s *scope) getstruct(name string) (*structdef, bool) {
for e := s.blockscopes.Back(); e != nil; e = e.Prev() {
bs := e.Value.(*blockscope)
if sd, ok := bs.structdefs[name]; ok {
return sd, ok
}
}

sd, ok := s.structdefs[name]
return sd, ok
}

func (s *scope) getobj(name string) (*obj, bool) {
for e := s.blockscopes.Back(); e != nil; e = e.Prev() {
bs := e.Value.(*blockscope)
Expand All @@ -51,15 +82,24 @@ func (s *scope) getobj(name string) (*obj, bool) {
return o, ok
}

func (s *scope) getglobstruct(name string) (*structdef, bool) {
sd, ok := s.structdefs[name]
return sd, ok
}

func (s *scope) getglobobj(name string) (*obj, bool) {
o, ok := s.objs[name]
return o, ok
}

type blockscope struct {
objs map[string]*obj
structdefs map[string]*structdef
}

func newblockscope() *blockscope {
return &blockscope{objs: map[string]*obj{}}
return &blockscope{
objs: map[string]*obj{},
structdefs: map[string]*structdef{},
}
}
7 changes: 7 additions & 0 deletions struct.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

type structdef struct {
name string
vars []string
defs []*obj
}
22 changes: 22 additions & 0 deletions tests/struct.sb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import assert

as = assert.assert

struct person{
name
age

def birthday() {
age += 1
}

def setname(n) {
name = n
}

def getname() {
return name
}
}

print("struct test succeeded")
2 changes: 2 additions & 0 deletions tokenize.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const (
tkBreak // break
tkReturn // return
tkImport // import
tkStruct // struct

tkIdent
tkStr
Expand All @@ -88,6 +89,7 @@ var keywords = []*strToTktype{
{"break", tkBreak},
{"return", tkReturn},
{"import", tkImport},
{"struct", tkStruct},
}

var punctuators = []*strToTktype{
Expand Down

0 comments on commit a9798ee

Please sign in to comment.