Skip to content

Commit

Permalink
feat, fix(parser): implement defer statement, add missing >>=, `<…
Browse files Browse the repository at this point in the history
…<=` , '&=', '|=', '^=' operators & some parser fixes
  • Loading branch information
saffage committed Jun 15, 2024
1 parent 2913c69 commit 78f8094
Show file tree
Hide file tree
Showing 34 changed files with 821 additions and 717 deletions.
22 changes: 20 additions & 2 deletions ast/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,11 @@ type (
TokPos token.Pos // `for` token.
}

Defer struct {
X Node
TokPos token.Pos // `defer` token.
}

Return struct {
X Node // optional
TokPos token.Pos // `return` token.
Expand Down Expand Up @@ -367,8 +372,20 @@ func (n *While) PosEnd() token.Pos { return n.Body.PosEnd() }
func (n *For) Pos() token.Pos { return n.TokPos }
func (n *For) PosEnd() token.Pos { return n.Body.PosEnd() }

func (n *Return) Pos() token.Pos { return n.TokPos }
func (n *Return) PosEnd() token.Pos { return n.X.PosEnd() }
func (n *Defer) Pos() token.Pos { return n.TokPos }
func (n *Defer) PosEnd() token.Pos { return n.X.PosEnd() }

func (n *Return) Pos() token.Pos { return n.TokPos }
func (n *Return) PosEnd() token.Pos {
if n.X != nil {
return n.X.PosEnd()
}
const length = len("return") - 1
end := n.TokPos
end.Char += uint32(length)
end.Offset += uint64(length)
return end
}

func (n *Break) Pos() token.Pos { return n.TokPos }
func (n *Break) PosEnd() token.Pos {
Expand Down Expand Up @@ -433,6 +450,7 @@ func (*If) implNode() {}
func (*Else) implNode() {}
func (*While) implNode() {}
func (*For) implNode() {}
func (*Defer) implNode() {}
func (*Return) implNode() {}
func (*Break) implNode() {}
func (*Continue) implNode() {}
Expand Down
27 changes: 17 additions & 10 deletions ast/operator_kind.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,27 @@ const (

// Prefix.

OperatorNot // !
OperatorNeg // -
OperatorAddrOf // &
OperatorPtr // *
OperatorEllipsis // ...
OperatorNot // !
OperatorNeg // -
OperatorAddrOf // &
OperatorMutAddrOf // &mut
OperatorPtr // *
OperatorMutPtr // *mut
OperatorEllipsis // ...

// Infix.

OperatorAssign // =
OperatorAddAndAssign // +=
OperatorSubAndAssign // -=
OperatorMultAndAssign // *=
OperatorDivAndAssign // /=
OperatorModAndAssign // %=
OperatorAddAssign // +=
OperatorSubAssign // -=
OperatorMultAssign // *=
OperatorDivAssign // /=
OperatorModAssign // %=
OperatorBitAndAssign // &=
OperatorBitOrAssign // |=
OperatorBitXorAssign // ^=
OperatorBitShlAssign // <<=
OperatorBitShrAssign // >>=
OperatorAdd // +
OperatorSub // -
OperatorMul // *
Expand Down
69 changes: 38 additions & 31 deletions ast/operator_kind_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion ast/repr.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,16 @@ func (n *For) Repr() string {
return fmt.Sprintf("for %s in %s %s", n.DeclList.Repr(), n.IterExpr.Repr(), n.Body.Repr())
}

func (n *Defer) Repr() string {
return fmt.Sprintf("defer %s", n.X.Repr())
}

func (n *Return) Repr() string {
return fmt.Sprintf("return %s", n.X.Repr())
if n.X != nil {
return fmt.Sprintf("return %s", n.X.Repr())
}

return "return"
}

func (n *Break) Repr() string {
Expand Down
5 changes: 5 additions & 0 deletions ast/walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ func (v Visitor) WalkTopDown(tree Node) {
v.WalkTopDown(n.IterExpr)
v.WalkTopDown(n.Body)

case *Defer:
assert(n.X != nil)

v.WalkTopDown(n.X)

case *Return:
if n.X != nil {
v.WalkTopDown(n.X)
Expand Down
3 changes: 2 additions & 1 deletion cgen/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ func Generate(w io.Writer, m *checker.Module) error {
gen := &generator{
Module: m,
out: bufio.NewWriter(w),
scope: m.Scope,
}

gen.out.WriteString(prelude)
Expand All @@ -20,7 +21,7 @@ func Generate(w io.Writer, m *checker.Module) error {
panic(err)
}

mainFn := gen.defs(gen.Defs, gen.Scope, false)
mainFn := gen.defs(gen.Defs, gen.Scope)
gen.initFunc()

if mainFn != nil {
Expand Down
63 changes: 57 additions & 6 deletions cgen/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,65 @@ import (
func (gen *generator) block(list *ast.StmtList, result *checker.Var) {
gen.line("{\n")
gen.indent++
for _, stmt := range list.Nodes[:len(list.Nodes)-1] {
gen.codeSect.WriteString(gen.StmtString(stmt))
}
if result != nil {
gen.assign(gen.name(result), list.Nodes[len(list.Nodes)-1])

if _, ok := scopeIDs[gen.scope]; !ok {
scopeIDs[gen.scope] = 0
} else {
gen.codeSect.WriteString(gen.StmtString(list.Nodes[len(list.Nodes)-1]))
scopeIDs[gen.scope]++
}

id := scopeIDs[gen.scope]
scope := gen.scope.Children()[id]

defer gen.setScope(gen.scope)
gen.setScope(scope)

var deferNodes []*ast.Defer

if len(list.Nodes) > 0 {
lastIdx := len(list.Nodes) - 1
lastNode := list.Nodes[lastIdx]

for _, stmt := range list.Nodes[:lastIdx] {
if deferNode, _ := stmt.(*ast.Defer); deferNode != nil {
println("deferred node: " + deferNode.Repr())
deferNodes = append(deferNodes, deferNode)
continue
}

gen.stmt(stmt)
}

if result != nil {
gen.assign(gen.name(result), lastNode)
} else if deferNode, _ := lastNode.(*ast.Defer); deferNode != nil {
println("deferred node: " + deferNode.Repr())
deferNodes = append(deferNodes, deferNode)
} else {
gen.stmt(lastNode)
}
}

for i := len(deferNodes) - 1; i >= 0; i-- {
gen.linef("L%d:;\n", gen.funcLabelID)
gen.funcLabelID++
gen.stmt(deferNodes[i].X)
}

delete(scopeIDs, gen.scope)
gen.indent--
gen.line("}\n")
}

func scopePath(scope *checker.Scope) string {
buf := ""
buf = scope.Name()

for s := scope.Parent(); s != nil; s = s.Parent() {
buf = s.Name() + " -> " + buf
}

return buf
}

var scopeIDs = map[*checker.Scope]int{}
5 changes: 3 additions & 2 deletions cgen/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,13 @@ func (gen *generator) builtInPrintln(call *ast.Call) string {
case types.KindUntypedString:
if value.Value != nil {
return fmt.Sprintf(
`fwrite(%[1]s"\n", 1, sizeof(%[1]s"\n"), stdout)`,
`fwrite(%[1]s"\n", 1, %d+1, stdout)`,
value.Value,
len(*constant.AsString(value.Value)),
)
} else {
return fmt.Sprintf(
`fwrite(%[1]s"\n", 1, sizeof(%[1]s"\n"), stdout)`,
`fwrite(%[1]s, 1, strlen(%[1]s), stdout); fwrite("\n", 1, 1, stdout)`,
gen.exprString(call.Args.Nodes[0]),
)
}
Expand Down
45 changes: 39 additions & 6 deletions cgen/exprs.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ func (gen *generator) exprString(expr ast.Node) string {
gen.block(node.StmtList, tmpVar)
return gen.name(tmpVar)

case *ast.Defer:
return ""

default:
fmt.Printf("not implemented '%T'\n", node)
}
Expand All @@ -215,7 +218,7 @@ func (gen *generator) exprString(expr ast.Node) string {

func (gen *generator) unary(x ast.Node, _ types.Type, op ast.OperatorKind) string {
switch op {
case ast.OperatorAddrOf:
case ast.OperatorAddrOf, ast.OperatorMutAddrOf:
return fmt.Sprintf("(&%s)", gen.exprString(x))

case ast.OperatorNot:
Expand Down Expand Up @@ -302,36 +305,66 @@ func (gen *generator) binary(x, y ast.Node, t types.Type, op ast.OperatorKind) s
gen.exprString(y),
)

case ast.OperatorAddAndAssign:
case ast.OperatorAddAssign:
return fmt.Sprintf("%s += %s",
gen.exprString(x),
gen.exprString(y),
)

case ast.OperatorSubAndAssign:
case ast.OperatorSubAssign:
return fmt.Sprintf("%s -= %s",
gen.exprString(x),
gen.exprString(y),
)

case ast.OperatorMultAndAssign:
case ast.OperatorMultAssign:
return fmt.Sprintf("%s *= %s",
gen.exprString(x),
gen.exprString(y),
)

case ast.OperatorDivAndAssign:
case ast.OperatorDivAssign:
return fmt.Sprintf("%s /= %s",
gen.exprString(x),
gen.exprString(y),
)

case ast.OperatorModAndAssign:
case ast.OperatorModAssign:
return fmt.Sprintf("%s %%= %s",
gen.exprString(x),
gen.exprString(y),
)

case ast.OperatorBitAndAssign:
return fmt.Sprintf("%s &= %s",
gen.exprString(x),
gen.exprString(y),
)

case ast.OperatorBitOrAssign:
return fmt.Sprintf("%s |= %s",
gen.exprString(x),
gen.exprString(y),
)

case ast.OperatorBitXorAssign:
return fmt.Sprintf("%s ^= %s",
gen.exprString(x),
gen.exprString(y),
)

case ast.OperatorBitShlAssign:
return fmt.Sprintf("%s <<= %s",
gen.exprString(x),
gen.exprString(y),
)

case ast.OperatorBitShrAssign:
return fmt.Sprintf("%s >>= %s",
gen.exprString(x),
gen.exprString(y),
)

default:
panic(fmt.Sprintf("not a binary operator: '%s'", op))
}
Expand Down
Loading

0 comments on commit 78f8094

Please sign in to comment.