Skip to content

Commit

Permalink
Merge #157
Browse files Browse the repository at this point in the history
157: parser, compiler: implement remaining variations of variable declaration r=zegl a=zegl

Fixes #136 
Fixes #156 

Co-authored-by: Gustav Westling <[email protected]>
  • Loading branch information
bors[bot] and zegl authored Jan 12, 2020
2 parents 1e4b1e6 + 02a7205 commit 40793bf
Show file tree
Hide file tree
Showing 8 changed files with 276 additions and 68 deletions.
82 changes: 40 additions & 42 deletions compiler/compiler/alloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,51 +21,49 @@ func (c *Compiler) compileAllocNode(v *parser.AllocNode) {
}()

// Allocate from type
if len(v.Val) == 1 {
if typeNode, ok := v.Val[0].(parser.TypeNode); ok {
treType := c.parserTypeToType(typeNode)

var val llvmValue.Value
var block *ir.Block

// Package level variables
if c.contextBlock == nil {
globType := treType.LLVM()
glob := c.module.NewGlobal(name.Var(v.Name[0]), globType)
glob.Init = constant.NewZeroInitializer(globType)

c.currentPackage.DefinePkgVar(v.Name[0], value.Value{
Value: glob,
Type: treType,
IsVariable: true,
})

val = glob
block = c.initGlobalsFunc.Blocks[0]
} else {
alloc := c.contextBlock.NewAlloca(treType.LLVM())
alloc.SetName(name.Var(v.Name[0]))

c.setVar(v.Name[0], value.Value{
Value: alloc,
Type: treType,
IsVariable: true,
})

val = alloc
block = c.contextBlock
}
if len(v.Val) == 0 && v.Type != nil {
treType := c.parserTypeToType(v.Type)

// Set to zero values
// TODO: Make slices less special
if sliceType, ok := treType.(*types.Slice); ok {
sliceType.SliceZero(block, c.externalFuncs.Malloc.Value.(llvmValue.Named), 2, val)
} else {
treType.Zero(block, val)
}
var val llvmValue.Value
var block *ir.Block

return
// Package level variables
if c.contextBlock == nil {
globType := treType.LLVM()
glob := c.module.NewGlobal(name.Var(v.Name[0]), globType)
glob.Init = constant.NewZeroInitializer(globType)

c.currentPackage.DefinePkgVar(v.Name[0], value.Value{
Value: glob,
Type: treType,
IsVariable: true,
})

val = glob
block = c.initGlobalsFunc.Blocks[0]
} else {
alloc := c.contextBlock.NewAlloca(treType.LLVM())
alloc.SetName(name.Var(v.Name[0]))

c.setVar(v.Name[0], value.Value{
Value: alloc,
Type: treType,
IsVariable: true,
})

val = alloc
block = c.contextBlock
}

// Set to zero values
// TODO: Make slices less special
if sliceType, ok := treType.(*types.Slice); ok {
sliceType.SliceZero(block, c.externalFuncs.Malloc.Value.(llvmValue.Named), 2, val)
} else {
treType.Zero(block, val)
}

return
}

for valIndex, valNode := range v.Val {
Expand Down
4 changes: 4 additions & 0 deletions compiler/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ func (c *Compiler) compile(instructions []parser.Node) {
c.compileReturnNode(v)
case *parser.AllocNode:
c.compileAllocNode(v)
case *parser.AllocGroup:
for _, a := range v.Allocs {
c.compileAllocNode(a)
}
case *parser.AssignNode:
c.compileAssignNode(v)
case *parser.ForNode:
Expand Down
2 changes: 1 addition & 1 deletion compiler/lexer/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ func Lex(inputFullSource string) []Item {
}
}

res = append(res, Item{Type: EOF})
res = append(res, Item{Type: EOL}, Item{Type: EOF})

return res
}
30 changes: 21 additions & 9 deletions compiler/lexer/lexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ func TestLexerSimpleAdd(t *testing.T) {
{Type: IDENTIFIER, Val: "aa", Line: 1},
{Type: OPERATOR, Val: "+", Line: 1},
{Type: IDENTIFIER, Val: "b", Line: 1},
{Type: EOF, Val: ""},
{Type: EOL},
{Type: EOF},
}

assert.Equal(t, expected, r)
Expand All @@ -33,7 +34,8 @@ func TestLexerSimpleAddWithNewlines(t *testing.T) {
{Type: OPERATOR, Val: "+", Line: 2},
{Type: IDENTIFIER, Val: "b", Line: 2},

{Type: EOF, Val: ""},
{Type: EOL},
{Type: EOF},
}

assert.Equal(t, expected, r)
Expand All @@ -46,7 +48,9 @@ func TestLexerSimpleAddNumber(t *testing.T) {
{Type: IDENTIFIER, Val: "aa", Line: 1},
{Type: OPERATOR, Val: "+", Line: 1},
{Type: NUMBER, Val: "14", Line: 1},
{Type: EOF, Val: ""},

{Type: EOL},
{Type: EOF},
}

assert.Equal(t, expected, r)
Expand All @@ -60,7 +64,9 @@ func TestLexerSimpleCall(t *testing.T) {
{Type: OPERATOR, Val: "(", Line: 1},
{Type: IDENTIFIER, Val: "bar", Line: 1},
{Type: OPERATOR, Val: ")", Line: 1},
{Type: EOF, Val: ""},

{Type: EOL},
{Type: EOF},
}

assert.Equal(t, expected, r)
Expand All @@ -74,7 +80,9 @@ func TestLexerSimpleCallWithString(t *testing.T) {
{Type: OPERATOR, Val: "(", Line: 1},
{Type: STRING, Val: "bar", Line: 1},
{Type: OPERATOR, Val: ")", Line: 1},
{Type: EOF, Val: ""},

{Type: EOL},
{Type: EOF},
}

assert.Equal(t, expected, r)
Expand All @@ -85,7 +93,8 @@ func TestString(t *testing.T) {

expected := []Item{
{Type: STRING, Val: "bar", Line: 1},
{Type: EOF, Val: ""},
{Type: EOL},
{Type: EOF},
}

assert.Equal(t, expected, r)
Expand All @@ -96,7 +105,8 @@ func TestEscapedString(t *testing.T) {

expected := []Item{
{Type: STRING, Val: "bar\"", Line: 1},
{Type: EOF, Val: ""},
{Type: EOL},
{Type: EOF},
}

assert.Equal(t, expected, r)
Expand All @@ -112,7 +122,8 @@ func TestLexerSimpleCallWithTwoStrings(t *testing.T) {
{Type: OPERATOR, Val: ",", Line: 1},
{Type: STRING, Val: "baz", Line: 1},
{Type: OPERATOR, Val: ")", Line: 1},
{Type: EOF, Val: ""},
{Type: EOL},
{Type: EOF},
}

assert.Equal(t, expected, r)
Expand All @@ -128,7 +139,8 @@ func TestLexerSimpleCallWithStringNum(t *testing.T) {
{Type: OPERATOR, Val: ",", Line: 1},
{Type: NUMBER, Val: "123", Line: 1},
{Type: OPERATOR, Val: ")", Line: 1},
{Type: EOF, Val: ""},
{Type: EOL},
{Type: EOF},
}

assert.Equal(t, expected, r)
Expand Down
13 changes: 12 additions & 1 deletion compiler/parser/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,21 @@ type AllocNode struct {

Name []string
Val []Node

Type TypeNode // Is set when allocating on the format "var ident int" and "var ident, ident int = expr, expr"
}

func (an AllocNode) String() string {
return fmt.Sprintf("alloc(%s) = %v (escapes: %v)", an.Name, an.Val, an.Escapes)
return fmt.Sprintf("alloc(%s) = %v (escapes: %v type: %v)", an.Name, an.Val, an.Escapes, an.Type)
}

type AllocGroup struct {
baseNode
Allocs []*AllocNode
}

func (an AllocGroup) String() string {
return fmt.Sprintf("alloc(%+v)", an.Allocs)
}

// AssignNode assign Val to Target (or Name)
Expand Down
89 changes: 76 additions & 13 deletions compiler/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -530,22 +530,26 @@ func (p *parser) parseOneWithOptions(withAheadParse, withArithAhead, withIdentif
if current.Val == "var" {
p.i++

name := p.lookAhead(0)
if name.Type != lexer.IDENTIFIER {
panic("expected IDENTIFIER after var")
}

p.i++
isGroup := p.lookAhead(0)
if isGroup.Val == "(" {
p.i++

tp, err := p.parseOneType()
if err != nil {
panic(err)
var allocs []*AllocNode
for {
nextToken := p.lookAhead(0)
if nextToken.Val == ")" {
break
}
if nextToken.Type == lexer.EOL {
p.i++
continue
}
allocs = append(allocs, p.parseVarDecl())
}
return &AllocGroup{Allocs: allocs}
}

return &AllocNode{
Name: []string{name.Val},
Val: []Node{tp},
}
return p.parseVarDecl()
}

if current.Val == "package" {
Expand Down Expand Up @@ -608,6 +612,65 @@ func (p *parser) parseOneWithOptions(withAheadParse, withArithAhead, withIdentif
panic("")
}

func (p *parser) parseVarDecl() *AllocNode {
allocNode := &AllocNode{Name: p.identifierList()}

isEq := p.lookAhead(0)
if isEq.Type == lexer.OPERATOR && isEq.Val == "=" {
p.i++
allocNode.Val = p.expressionList()
return allocNode
} else {
tp, err := p.parseOneType()
if err != nil {
panic(err)
}
allocNode.Type = tp
p.i++
}

isEq = p.lookAhead(0)
if isEq.Type == lexer.OPERATOR && isEq.Val == "=" {
p.i++
allocNode.Val = p.expressionList()
}

return allocNode
}

func (p *parser) identifierList() (res []string) {
for {
n := p.lookAhead(0)
p.expect(n, lexer.Item{Type: lexer.IDENTIFIER})
res = append(res, n.Val)

p.i++

isComma := p.lookAhead(0)
if isComma.Type == lexer.OPERATOR && isComma.Val == "," {
p.i++
continue
}

return
}
}

func (p *parser) expressionList() (res []Node) {
for {
res = append(res, p.parseOne(true))
p.i++

isComma := p.lookAhead(0)
if isComma.Type == lexer.OPERATOR && isComma.Val == "," {
p.i++
continue
}

return
}
}

func (p *parser) aheadParse(input Node) Node {
return p.aheadParseWithOptions(input, true, true)
}
Expand Down
Loading

0 comments on commit 40793bf

Please sign in to comment.