Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decouple parse & resolve steps #148

Merged
merged 58 commits into from
Sep 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
6d42e3d
decoupling parse/resolve
xonixx Aug 25, 2022
62c0e91
decoupling parse/resolve
xonixx Aug 25, 2022
6f97aea
decoupling parse/resolve
xonixx Aug 25, 2022
a2bb302
decoupling parse/resolve
xonixx Aug 25, 2022
4a93430
decoupling parse/resolve
xonixx Aug 25, 2022
f4b7a25
decoupling parse/resolve : functions
xonixx Aug 25, 2022
fac460d
decoupling parse/resolve : visitor approach from golang
xonixx Aug 25, 2022
55b69ad
decoupling parse/resolve
xonixx Aug 25, 2022
bab57ba
decoupling parse/resolve : visitor approach from golang
xonixx Aug 25, 2022
da3f570
decoupling parse/resolve
xonixx Aug 25, 2022
bf2a0ea
decoupling parse/resolve : multiExpr
xonixx Aug 25, 2022
4214783
decoupling parse/resolve : rfct
xonixx Aug 25, 2022
04e70d7
decoupling parse/resolve : rfct
xonixx Aug 25, 2022
6ff111c
decoupling parse/resolve : rfct
xonixx Aug 25, 2022
d1d5edf
decoupling parse/resolve : work on sufficient position wiring for res…
xonixx Aug 29, 2022
945e48e
decoupling parse/resolve : varRef/arrayRef
xonixx Aug 29, 2022
6727e86
decoupling parse/resolve : varRef/arrayRef
xonixx Aug 29, 2022
d668547
decoupling parse/resolve
xonixx Aug 29, 2022
2b6f2e6
decoupling parse/resolve
xonixx Aug 29, 2022
2e26c0e
decoupling parse/resolve : fight with import cycles
xonixx Aug 29, 2022
b63e992
decoupling parse/resolve : fight with import cycles
xonixx Aug 29, 2022
3219855
decoupling parse/resolve : fight with import cycles
xonixx Aug 29, 2022
25d2860
decoupling parse/resolve : fixing failing tests
xonixx Aug 30, 2022
fdd96be
decoupling parse/resolve : fixing failing tests
xonixx Aug 30, 2022
9399ab1
decoupling parse/resolve : fixing failing tests
xonixx Aug 30, 2022
d801d4b
decoupling parse/resolve : fixing failing tests
xonixx Aug 30, 2022
2fc4749
decoupling parse/resolve : fixing failing tests
xonixx Aug 30, 2022
e7279c4
decoupling parse/resolve : fixing failing tests
xonixx Aug 30, 2022
ecbdeea
decoupling parse/resolve : fixing failing tests
xonixx Aug 30, 2022
6078dd5
decoupling parse/resolve : rfct
xonixx Aug 30, 2022
3e33f1d
decoupling parse/resolve : rfct
xonixx Aug 30, 2022
6755890
decoupling parse/resolve : rfct
xonixx Aug 30, 2022
4d1a2f6
decoupling parse/resolve : rfct
xonixx Aug 30, 2022
2c44707
decoupling parse/resolve : cleanup
xonixx Aug 30, 2022
f8e6e70
decoupling parse/resolve : cleanup
xonixx Aug 30, 2022
7c1029e
decoupling parse/resolve : rfct
xonixx Aug 30, 2022
05aaace
decoupling parse/resolve : cleanup
xonixx Aug 30, 2022
c858f36
decoupling parse/resolve : rfct
xonixx Aug 30, 2022
b55f6f4
decoupling parse/resolve : rfct
xonixx Aug 30, 2022
0b1d67d
Merge branch 'master' into decouple_parse_resolve
xonixx Aug 31, 2022
787ffd3
decoupling parse/resolve : CR : adding `node()` to `Node` interface
xonixx Sep 12, 2022
7faa3a8
decoupling parse/resolve : CR : renaming
xonixx Sep 12, 2022
478b645
decoupling parse/resolve : CR : adjust comment for Walk function
xonixx Sep 12, 2022
5a58be1
decoupling parse/resolve : CR : `WillBeResolvedLater` -> `resolvedLater`
xonixx Sep 12, 2022
2c07a7a
decoupling parse/resolve : CR : cleanup comment
xonixx Sep 12, 2022
b039569
decoupling parse/resolve : CR : Let's change `parser.function()` to r…
xonixx Sep 12, 2022
ee75278
decoupling parse/resolve : CR : removing `EndPos` since was used in s…
xonixx Sep 12, 2022
7cd38cc
decoupling parse/resolve : CR : remove `Position.Add()` and adjust er…
xonixx Sep 12, 2022
8b65e32
decoupling parse/resolve : CR : move `PositionError` to `ast`
xonixx Sep 13, 2022
7b6e450
decoupling parse/resolve : CR : rfct
xonixx Sep 13, 2022
8794caa
decoupling parse/resolve : CR : restore fields back to `ParseError`
xonixx Sep 13, 2022
3be851f
decoupling parse/resolve : CR : restore fields back to `ParseError`
xonixx Sep 13, 2022
198768e
decoupling parse/resolve : CR : add missing comment
xonixx Sep 13, 2022
40bb5ff
decoupling parse/resolve : CR : add missing comment
xonixx Sep 13, 2022
f641fbf
decoupling parse/resolve : CR : add missing comment
xonixx Sep 13, 2022
b590a5c
decoupling parse/resolve : CR : add missing comment
xonixx Sep 13, 2022
3cf4905
decoupling parse/resolve : CR : `newResolver`
xonixx Sep 13, 2022
5f10a7d
decoupling parse/resolve : CR : fix comment
xonixx Sep 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 99 additions & 4 deletions internal/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@ import (
// Program is an entire AWK program.
type Program struct {
Begin []Stmts
Actions []Action
Actions []*Action
End []Stmts
Functions []Function
Scalars map[string]int
Arrays map[string]int
Functions []*Function
}

// ResolvedProgram is a parsed AWK program + additional data prepared by resolve step
// needed for subsequent interpretation
type ResolvedProgram struct {
xonixx marked this conversation as resolved.
Show resolved Hide resolved
Program
Scalars map[string]int
Arrays map[string]int
}

// String returns an indented, pretty-printed version of the parsed
Expand Down Expand Up @@ -75,8 +81,54 @@ func (a *Action) String() string {
return strings.Join(patterns, ", ") + sep + stmtsStr
}

// Node is an interface to be satisfied by all AST elements.
// We need it to be able to work with AST in a generic way, like in ast.Walk().
type Node interface {
xonixx marked this conversation as resolved.
Show resolved Hide resolved
node()
}

// All these types implement the Node interface.
func (p *Program) node() {}
func (a *Action) node() {}
func (f *Function) node() {}
func (e *FieldExpr) node() {}
func (e *NamedFieldExpr) node() {}
func (e *UnaryExpr) node() {}
func (e *BinaryExpr) node() {}
func (e *ArrayExpr) node() {}
func (e *InExpr) node() {}
func (e *CondExpr) node() {}
func (e *NumExpr) node() {}
func (e *StrExpr) node() {}
func (e *RegExpr) node() {}
func (e *VarExpr) node() {}
func (e *IndexExpr) node() {}
func (e *AssignExpr) node() {}
func (e *AugAssignExpr) node() {}
func (e *IncrExpr) node() {}
func (e *CallExpr) node() {}
func (e *UserCallExpr) node() {}
func (e *MultiExpr) node() {}
func (e *GetlineExpr) node() {}
func (s *PrintStmt) node() {}
func (s *PrintfStmt) node() {}
func (s *ExprStmt) node() {}
func (s *IfStmt) node() {}
func (s *ForStmt) node() {}
func (s *ForInStmt) node() {}
func (s *WhileStmt) node() {}
func (s *DoWhileStmt) node() {}
func (s *BreakStmt) node() {}
func (s *ContinueStmt) node() {}
func (s *NextStmt) node() {}
func (s *ExitStmt) node() {}
func (s *DeleteStmt) node() {}
func (s *ReturnStmt) node() {}
func (s *BlockStmt) node() {}

// Expr is the abstract syntax tree for any AWK expression.
type Expr interface {
Node
expr()
String() string
}
Expand Down Expand Up @@ -154,6 +206,7 @@ type ArrayExpr struct {
Scope VarScope
Index int
Name string
Pos Position
}

func (e *ArrayExpr) String() string {
Expand Down Expand Up @@ -221,6 +274,9 @@ func (e *RegExpr) String() string {
return "/" + escaped + "/"
}

// meaning it will be set during resolve step
const resolvedLater = -1

type VarScope int

const (
Expand All @@ -236,6 +292,7 @@ type VarExpr struct {
Scope VarScope
Index int
Name string
Pos Position
}

func (e *VarExpr) String() string {
Expand Down Expand Up @@ -315,6 +372,7 @@ type UserCallExpr struct {
Index int
Name string
Args []Expr
Pos Position
}

func (e *UserCallExpr) String() string {
Expand Down Expand Up @@ -375,6 +433,7 @@ func IsLValue(expr Expr) bool {

// Stmt is the abstract syntax tree for any AWK statement.
type Stmt interface {
Node
stmt()
String() string
}
Expand Down Expand Up @@ -585,6 +644,7 @@ type Function struct {
Params []string
Arrays []bool
Body Stmts
Pos Position
}

func (f *Function) String() string {
Expand All @@ -598,3 +658,38 @@ func trimParens(s string) string {
}
return s
}

// VarRef is a constructor for *VarExpr
func VarRef(name string, pos Position) *VarExpr {
xonixx marked this conversation as resolved.
Show resolved Hide resolved
return &VarExpr{resolvedLater, resolvedLater, name, pos}
}

// ArrayRef is a constructor for *ArrayExpr
func ArrayRef(name string, pos Position) *ArrayExpr {
return &ArrayExpr{resolvedLater, resolvedLater, name, pos}
}

// UserCall is a constructor for *UserCallExpr
func UserCall(name string, args []Expr, pos Position) *UserCallExpr {
return &UserCallExpr{false, resolvedLater, name, args, pos}
}

// PositionError represents an error bound to specific position in source.
type PositionError struct {
// Source line/column position where the error occurred.
Position Position
// Error message.
Message string
}

// PosErrorf like fmt.Errorf, but with an explicit position.
func PosErrorf(pos Position, format string, args ...interface{}) error {
message := fmt.Sprintf(format, args...)
return &PositionError{pos, message}
}

// Error returns a formatted version of the error, including the line
// and column numbers.
func (e *PositionError) Error() string {
return fmt.Sprintf("parse error at %d:%d: %s", e.Position.Line, e.Position.Column, e.Message)
}
180 changes: 180 additions & 0 deletions internal/ast/walk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package ast
xonixx marked this conversation as resolved.
Show resolved Hide resolved

import "fmt"

// A Visitor's Visit method is invoked for each node encountered by Walk.
xonixx marked this conversation as resolved.
Show resolved Hide resolved
// If the result visitor w is not nil, Walk visits each of the children
// of node with the visitor w, followed by a call of w.Visit(nil).
type Visitor interface {
Visit(node Node) (w Visitor)
}

// WalkExprList walks a visitor over a list of expression AST nodes
func WalkExprList(v Visitor, exprs []Expr) {
for _, expr := range exprs {
Walk(v, expr)
}
}

// WalkStmtList walks a visitor over a list of statement AST nodes
func WalkStmtList(v Visitor, stmts []Stmt) {
for _, stmt := range stmts {
Walk(v, stmt)
}
}

// Walk traverses an AST in depth-first order: It starts by calling
// v.Visit(node); if node is nil, it does nothing. If the visitor w returned by
// v.Visit(node) is not nil, Walk is invoked recursively with visitor
// w for each of the non-nil children of node, followed by a call of
// w.Visit(nil).
//
func Walk(v Visitor, node Node) {
if node == nil {
xonixx marked this conversation as resolved.
Show resolved Hide resolved
return
}
if v = v.Visit(node); v == nil {
return
}

// walk children
// (the order of the cases matches the order
// of the corresponding node types in ast.go)
switch n := node.(type) {

// expressions
case *FieldExpr:
Walk(v, n.Index)

case *NamedFieldExpr:
Walk(v, n.Field)

case *UnaryExpr:
Walk(v, n.Value)

case *BinaryExpr:
Walk(v, n.Left)
Walk(v, n.Right)

case *ArrayExpr: // leaf
case *InExpr:
WalkExprList(v, n.Index)
Walk(v, n.Array)

case *CondExpr:
Walk(v, n.Cond)
Walk(v, n.True)
Walk(v, n.False)

case *NumExpr: // leaf
case *StrExpr: // leaf
case *RegExpr: // leaf
case *VarExpr: // leaf
case *IndexExpr:
Walk(v, n.Array)
WalkExprList(v, n.Index)

case *AssignExpr:
Walk(v, n.Left)
Walk(v, n.Right)

case *AugAssignExpr:
Walk(v, n.Left)
Walk(v, n.Right)

case *IncrExpr:
Walk(v, n.Expr)

case *CallExpr:
WalkExprList(v, n.Args)

case *UserCallExpr:
WalkExprList(v, n.Args)

case *MultiExpr:
WalkExprList(v, n.Exprs)

case *GetlineExpr:
Walk(v, n.Command)
Walk(v, n.Target)
Walk(v, n.File)

// statements
case *PrintStmt:
WalkExprList(v, n.Args)
Walk(v, n.Dest)

case *PrintfStmt:
WalkExprList(v, n.Args)
Walk(v, n.Dest)

case *ExprStmt:
Walk(v, n.Expr)

case *IfStmt:
Walk(v, n.Cond)
WalkStmtList(v, n.Body)
WalkStmtList(v, n.Else)

case *ForStmt:
Walk(v, n.Pre)
Walk(v, n.Cond)
Walk(v, n.Post)
WalkStmtList(v, n.Body)

case *ForInStmt:
Walk(v, n.Var)
Walk(v, n.Array)
WalkStmtList(v, n.Body)

case *WhileStmt:
Walk(v, n.Cond)
WalkStmtList(v, n.Body)

case *DoWhileStmt:
WalkStmtList(v, n.Body)
Walk(v, n.Cond)

case *BreakStmt: // leaf
case *ContinueStmt: // leaf
case *NextStmt: // leaf
case *ExitStmt:
Walk(v, n.Status)

case *DeleteStmt:
Walk(v, n.Array)
WalkExprList(v, n.Index)

case *ReturnStmt:
Walk(v, n.Value)

case *BlockStmt:
WalkStmtList(v, n.Body)

case *Program:
for _, stmts := range n.Begin {
WalkStmtList(v, stmts)
}
for _, action := range n.Actions {
Walk(v, action)
}
for _, function := range n.Functions {
Walk(v, function)
}
for _, stmts := range n.End {
WalkStmtList(v, stmts)
}

case *Action:
WalkExprList(v, n.Pattern)
WalkStmtList(v, n.Stmts)

case *Function:
WalkStmtList(v, n.Body)

default:
panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n))
}

v.Visit(nil)
}
2 changes: 1 addition & 1 deletion internal/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (e *compileError) Error() string {
}

// Compile compiles an AST (parsed program) into virtual machine instructions.
func Compile(prog *ast.Program) (compiledProg *Program, err error) {
func Compile(prog *ast.ResolvedProgram) (compiledProg *Program, err error) {
defer func() {
// The compiler uses panic with a *compileError to signal compile
// errors internally, and they're caught here. This avoids the
Expand Down
Loading