Skip to content

Commit

Permalink
Made ast-types type-safe #19
Browse files Browse the repository at this point in the history
  • Loading branch information
dbaumgarten committed Nov 26, 2020
1 parent 2b018c5 commit 08372f0
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 22 deletions.
2 changes: 1 addition & 1 deletion pkg/nolol/converter_macros.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func (c *Converter) replacePlaceholders(m ast.Node, replacements map[string]ast.
if deref, is := node.(*ast.Dereference); is && visitType == ast.SingleVisit {
lvarname := strings.ToLower(deref.Variable)
if replacement, exists := replacements[lvarname]; exists {
replacement = nast.CopyAst(replacement)
replacement = nast.CopyAst(replacement).(ast.Expression)
if replacementVariable, isvar := replacement.(*ast.Dereference); isvar {
if deref.Operator != "" && replacementVariable.Operator != "" {
return &parser.Error{
Expand Down
67 changes: 67 additions & 0 deletions pkg/nolol/nast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,15 @@ func (n *Program) End() ast.Position {
// inside a nolol program
type Element interface {
ast.Node
// Dummy marker-method
El()
}

// NestableElement describes a special kind of element, that can appear inside blocks (and not only on the top-level)
type NestableElement interface {
Element
// Dummy marker-method
NestEl()
}

// StatementLine is a line consisting of yolol-statements
Expand All @@ -52,6 +56,12 @@ func (n *StatementLine) Start() ast.Position {
return n.Position
}

// El implements the type-marker method
func (n *StatementLine) El() {}

// NestEl implements the type-marker method
func (n *StatementLine) NestEl() {}

// Definition declares a constant
type Definition struct {
Position ast.Position
Expand All @@ -73,6 +83,9 @@ func (n *Definition) End() ast.Position {
return n.Value.End()
}

// El implements the type-marker method
func (n *Definition) El() {}

// Block represents a block/group of elements, for example inside an if
type Block struct {
Elements []NestableElement
Expand All @@ -94,6 +107,12 @@ func (n *Block) End() ast.Position {
return n.Elements[len(n.Elements)-1].End()
}

// El implements the type-marker method
func (n *Block) El() {}

// NestEl implements the type-marker method
func (n *Block) NestEl() {}

// MultilineIf represents a nolol-style multiline if
type MultilineIf struct {
Positions []ast.Position
Expand Down Expand Up @@ -121,6 +140,12 @@ func (n *MultilineIf) End() ast.Position {
return n.ElseBlock.End()
}

// El implements the type-marker method
func (n *MultilineIf) El() {}

// NestEl implements the type-marker method
func (n *MultilineIf) NestEl() {}

// GoToLabelStatement represents a goto to a line-label
type GoToLabelStatement struct {
Position ast.Position
Expand All @@ -137,6 +162,9 @@ func (n *GoToLabelStatement) End() ast.Position {
return n.Position.Add(len(n.Label) + 1)
}

// Stmt implements type-checking dummy-func
func (n *GoToLabelStatement) Stmt() {}

// WhileLoop represents a nolol-style while loop
type WhileLoop struct {
Position ast.Position
Expand All @@ -157,6 +185,12 @@ func (n *WhileLoop) End() ast.Position {
return n.Block.End()
}

// El implements the type-marker method
func (n *WhileLoop) El() {}

// NestEl implements the type-marker method
func (n *WhileLoop) NestEl() {}

// WaitDirective blocks execution as long as the condition is true
type WaitDirective struct {
Position ast.Position
Expand All @@ -180,6 +214,12 @@ func (n *WaitDirective) End() ast.Position {
return n.Statements[len(n.Statements)-1].End()
}

// El implements the type-marker method
func (n *WaitDirective) El() {}

// NestEl implements the type-marker method
func (n *WaitDirective) NestEl() {}

// IncludeDirective represents the inclusion of another file in the source-file
type IncludeDirective struct {
Position ast.Position
Expand All @@ -196,6 +236,9 @@ func (n *IncludeDirective) End() ast.Position {
return n.Position.Add(len(n.File) + 3 + len("include"))
}

// El implements the type-marker method
func (n *IncludeDirective) El() {}

// MacroDefinition represents the definition of a macro
type MacroDefinition struct {
Position ast.Position
Expand All @@ -218,6 +261,9 @@ func (n *MacroDefinition) End() ast.Position {
return n.Block.End()
}

// El implements the type-marker method
func (n *MacroDefinition) El() {}

// MacroInsetion represents the use of a macro
// To reduce code-duplication it re-uses the FuncCall-type
type MacroInsetion struct {
Expand All @@ -238,6 +284,12 @@ func (n *MacroInsetion) End() ast.Position {
return n.FuncCall.End()
}

// El implements the type-marker method
func (n *MacroInsetion) El() {}

// NestEl implements the type-marker method
func (n *MacroInsetion) NestEl() {}

// Trigger is a special kind of node, that is sometimes inserted during code-generation
// It is used to tigger certain events when reached by a visitor and is created typically by nodes that
// replace themselves, but want to perform a certain action when a specific point in the ast is visited again.
Expand All @@ -255,6 +307,12 @@ func (n *Trigger) End() ast.Position {
return ast.Position{}
}

// El implements the type-marker method
func (n *Trigger) El() {}

// NestEl implements the type-marker method
func (n *Trigger) NestEl() {}

// FuncCall represents a func-call
type FuncCall struct {
Position ast.Position
Expand All @@ -275,6 +333,9 @@ func (n *FuncCall) End() ast.Position {
return n.Position.Add(len(n.Function) + 2)
}

// Expr implements type-checking dummy-func
func (n *FuncCall) Expr() {}

// BreakStatement represents the break-keyword inside a loop
type BreakStatement struct {
Position ast.Position
Expand All @@ -290,6 +351,9 @@ func (n *BreakStatement) End() ast.Position {
return n.Position.Add(len("break"))
}

// Stmt implements type-checking dummy-func
func (n *BreakStatement) Stmt() {}

// ContinueStatement represents the continue-keyword inside a loop
type ContinueStatement struct {
Position ast.Position
Expand All @@ -304,3 +368,6 @@ func (n *ContinueStatement) Start() ast.Position {
func (n *ContinueStatement) End() ast.Position {
return n.Position.Add(len("continue"))
}

// Stmt implements type-checking dummy-func
func (n *ContinueStatement) Stmt() {}
10 changes: 5 additions & 5 deletions pkg/nolol/nast/visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (l *Definition) Accept(v ast.Visitor) error {
if err != nil {
return err
}
l.Value, err = ast.AcceptChild(v, l.Value)
l.Value, err = ast.MustExpression(ast.AcceptChild(v, l.Value))
if err != nil {
return err
}
Expand Down Expand Up @@ -83,7 +83,7 @@ func (s *MultilineIf) Accept(v ast.Visitor) error {
if err != nil {
return err
}
s.Conditions[i], err = ast.AcceptChild(v, s.Conditions[i])
s.Conditions[i], err = ast.MustExpression(ast.AcceptChild(v, s.Conditions[i]))
if err != nil {
return err
}
Expand Down Expand Up @@ -117,7 +117,7 @@ func (s *WhileLoop) Accept(v ast.Visitor) error {
if err != nil {
return err
}
s.Condition, err = ast.AcceptChild(v, s.Condition)
s.Condition, err = ast.MustExpression(ast.AcceptChild(v, s.Condition))
if err != nil {
return err
}
Expand All @@ -139,7 +139,7 @@ func (s *WaitDirective) Accept(v ast.Visitor) error {
if err != nil {
return err
}
s.Condition, err = ast.AcceptChild(v, s.Condition)
s.Condition, err = ast.MustExpression(ast.AcceptChild(v, s.Condition))
if err != nil {
return err
}
Expand Down Expand Up @@ -297,7 +297,7 @@ func AcceptExpressionList(parent ast.Node, v ast.Visitor, old []ast.Expression)
new := make([]ast.Expression, 0, len(old)+len(repl.Replacement)-1)
new = append(new, old[:i]...)
for _, el := range repl.Replacement {
new = append(new, el.(NestableElement))
new = append(new, el.(ast.Expression))
}
new = append(new, old[i+1:]...)
old = new
Expand Down
4 changes: 2 additions & 2 deletions pkg/nolol/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ func (p *Parser) ParseDefinition() *nast.Definition {
}

// ParseMultilineIf parses a nolol-style multiline if
func (p *Parser) ParseMultilineIf() nast.Element {
func (p *Parser) ParseMultilineIf() nast.NestableElement {
p.Log()
mlif := nast.MultilineIf{
Positions: make([]ast.Position, 1),
Expand Down Expand Up @@ -455,7 +455,7 @@ func (p *Parser) ParseMultilineIf() nast.Element {
}

// ParseWhile pasres a nolol while
func (p *Parser) ParseWhile() nast.Element {
func (p *Parser) ParseWhile() nast.NestableElement {
p.Log()
loop := nast.WhileLoop{
Position: p.CurrentToken.Position,
Expand Down
6 changes: 3 additions & 3 deletions pkg/optimizers/expression_inversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ func (o ExpressionInversionOptimizer) Optimize(prog ast.Node) error {
// OptimizeExpression optimizes a single expression
// Optimize() in contrast can only optimize whole programms
func (o ExpressionInversionOptimizer) OptimizeExpression(e ast.Expression) ast.Expression {
e, _ = ast.AcceptChild(o, e)
e, _ = ast.MustExpression(ast.AcceptChild(o, e))
return e
}

func pushDownNots(node ast.Expression) ast.Expression {
func pushDownNots(node ast.Node) ast.Expression {
if op, is := node.(*ast.UnaryOperation); is {
if op.Operator == "not" {
switch inner := op.Exp.(type) {
Expand Down Expand Up @@ -67,7 +67,7 @@ func pushDownNots(node ast.Expression) ast.Expression {
return nil
}

func bubbleUpNots(node ast.Expression) ast.Expression {
func bubbleUpNots(node ast.Node) ast.Expression {
if bin, isbinary := node.(*ast.BinaryOperation); isbinary {
l, lisunary := bin.Exp1.(*ast.UnaryOperation)
r, risunary := bin.Exp2.(*ast.UnaryOperation)
Expand Down
2 changes: 1 addition & 1 deletion pkg/optimizers/static_expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func (o *StaticExpressionOptimizer) Optimize(prog ast.Node) error {

// OptimizeExpression optimizes a single expression recursively
func (o *StaticExpressionOptimizer) OptimizeExpression(e ast.Expression) ast.Expression {
e, _ = ast.AcceptChild(o, e)
e, _ = ast.MustExpression(ast.AcceptChild(o, e))
return e
}

Expand Down
31 changes: 31 additions & 0 deletions pkg/parser/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ func (n *Line) End() Position {
// Expression is the interface for all expressions
type Expression interface {
Node
// dummy function for type-safety
Expr()
}

// StringConstant represents a constant of type string
Expand All @@ -75,6 +77,9 @@ func (n *StringConstant) End() Position {
return pos
}

// Expr implements type-checking dummy-func
func (n *StringConstant) Expr() {}

// NumberConstant represents a constant of type number
type NumberConstant struct {
Position Position
Expand All @@ -92,6 +97,9 @@ func (n *NumberConstant) End() Position {
return n.Start().Add(len(n.Value))
}

// Expr implements type-checking dummy-func
func (n *NumberConstant) Expr() {}

// Dereference represents the dereferencing of a variable
type Dereference struct {
Position Position
Expand All @@ -115,6 +123,13 @@ func (n *Dereference) End() Position {
return n.Start().Add(len(n.Variable) + len(n.Operator))
}

// Expr implements type-checking dummy-func
func (n *Dereference) Expr() {}

// Stmt implements type-checking dummy-func
// Dereferences can be used as statement when combined with a pre/post-op
func (n *Dereference) Stmt() {}

// UnaryOperation represents a unary operation (-, not)
type UnaryOperation struct {
Position Position
Expand All @@ -135,6 +150,9 @@ func (n *UnaryOperation) End() Position {
return n.Exp.End()
}

// Expr implements type-checking dummy-func
func (n *UnaryOperation) Expr() {}

// BinaryOperation is a binary operation
type BinaryOperation struct {
Operator string
Expand All @@ -158,9 +176,13 @@ func (n *BinaryOperation) End() Position {
return n.Exp2.End()
}

// Expr implements type-checking dummy-func
func (n *BinaryOperation) Expr() {}

// Statement is the interface for all statements
type Statement interface {
Node
Stmt()
}

// Assignment represents the assignment to a variable
Expand All @@ -187,6 +209,9 @@ func (n *Assignment) End() Position {
return n.Value.End()
}

// Stmt implements type-checking dummy-func
func (n *Assignment) Stmt() {}

// IfStatement represents an if-statement
type IfStatement struct {
Position Position
Expand All @@ -211,6 +236,9 @@ func (n *IfStatement) End() Position {
return n.ElseBlock[len(n.ElseBlock)-1].End().Add(3)
}

// Stmt implements type-checking dummy-func
func (n *IfStatement) Stmt() {}

// GoToStatement represents a goto
type GoToStatement struct {
Position Position
Expand All @@ -230,3 +258,6 @@ func (n *GoToStatement) End() Position {
}
return n.Line.End()
}

// Stmt implements type-checking dummy-func
func (n *GoToStatement) Stmt() {}
Loading

0 comments on commit 08372f0

Please sign in to comment.